Merge branch 'main' into taochen/python-invoke-model-after-auto-invoke-exhausted

This commit is contained in:
Eduard van Valkenburg
2026-09-28 15:53:38 +02:00
committed by GitHub
1061 changed files with 21468 additions and 78553 deletions
+1
View File
@@ -32,6 +32,7 @@ extend-exclude = [
[default.extend-words]
ACI = "ACI" # Azure Container Instance
CPY = "CPY" # Ruff copyright lint rule prefix
exercize = "exercize" # test typos
gramatical = "gramatical" # test typos
Guid = "Guid" # Globally Unique Identifier
+116
View File
@@ -0,0 +1,116 @@
name: Get GitHub automation token
description: Creates a GitHub App installation token with a temporary PAT fallback
inputs:
mode:
description: Authentication mode (app, app-with-fallback, or pat)
required: false
default: app-with-fallback
azure-client-id:
description: Client ID of the Azure workload identity
required: false
azure-tenant-id:
description: Azure tenant ID
required: false
azure-subscription-id:
description: Azure subscription containing the Key Vault
required: false
key-vault-name:
description: Azure Key Vault name
required: false
key-name:
description: Key Vault key used to sign the GitHub App JWT
required: false
github-app-client-id:
description: GitHub App client ID
required: false
github-app-installation-id:
description: GitHub App installation ID
required: false
repository:
description: Repository to include in the installation token
required: false
permission-profile:
description: Permission profile (issues, pull-requests, or devflow)
required: true
fallback-token:
description: PAT used temporarily when app authentication is unavailable
required: false
outputs:
token:
description: GitHub App installation token or fallback PAT
value: ${{ steps.select-token.outputs.token }}
source:
description: Selected authentication source
value: ${{ steps.select-token.outputs.source }}
runs:
using: composite
steps:
- name: Validate authentication mode
shell: bash
env:
AUTH_MODE: ${{ inputs.mode || 'app-with-fallback' }}
run: |
if [[ "$AUTH_MODE" != "app" && "$AUTH_MODE" != "app-with-fallback" && "$AUTH_MODE" != "pat" ]]; then
echo "::error::Unsupported GitHub authentication mode."
exit 1
fi
- name: Sign in to Azure
id: azure-login
if: ${{ (inputs.mode || 'app-with-fallback') != 'pat' }}
continue-on-error: true
uses: azure/login@7ddb5af1ef8758cf1353cf3b42f940aee27ba21c # v3.0.2
with:
client-id: ${{ inputs.azure-client-id }}
tenant-id: ${{ inputs.azure-tenant-id }}
subscription-id: ${{ inputs.azure-subscription-id }}
- name: Create GitHub App installation token
id: app-token
if: ${{ (inputs.mode || 'app-with-fallback') != 'pat' && steps.azure-login.outcome == 'success' }}
continue-on-error: true
shell: bash
env:
AZURE_SUBSCRIPTION_ID: ${{ inputs.azure-subscription-id }}
KEY_VAULT_NAME: ${{ inputs.key-vault-name }}
KEY_NAME: ${{ inputs.key-name }}
GITHUB_APP_CLIENT_ID: ${{ inputs.github-app-client-id }}
GITHUB_APP_INSTALLATION_ID: ${{ inputs.github-app-installation-id }}
TARGET_REPOSITORY: ${{ inputs.repository }}
PERMISSION_PROFILE: ${{ inputs.permission-profile }}
run: |
token="$(node "$GITHUB_ACTION_PATH/create-token.js")"
echo "::add-mask::$token"
echo "token=$token" >> "$GITHUB_OUTPUT"
- name: Select authentication token
id: select-token
shell: bash
env:
AUTH_MODE: ${{ inputs.mode || 'app-with-fallback' }}
APP_TOKEN: ${{ steps.app-token.outputs.token }}
FALLBACK_TOKEN: ${{ inputs.fallback-token }}
run: |
if [[ "$AUTH_MODE" != "pat" && -n "$APP_TOKEN" ]]; then
token="$APP_TOKEN"
source="app"
echo "::notice::GitHub authentication source: app"
elif [[ "$AUTH_MODE" == "app-with-fallback" && -n "$FALLBACK_TOKEN" ]]; then
token="$FALLBACK_TOKEN"
source="pat-fallback"
echo "::warning::GitHub authentication source: PAT fallback"
elif [[ "$AUTH_MODE" == "pat" && -n "$FALLBACK_TOKEN" ]]; then
token="$FALLBACK_TOKEN"
source="pat-forced"
echo "::warning::GitHub authentication source: PAT (forced rollout mode)"
else
echo "::error::GitHub App authentication is unavailable and no fallback PAT was provided."
exit 1
fi
echo "::add-mask::$token"
echo "token=$token" >> "$GITHUB_OUTPUT"
echo "source=$source" >> "$GITHUB_OUTPUT"
@@ -0,0 +1,149 @@
// Copyright (c) Microsoft. All rights reserved.
const crypto = require('node:crypto');
const { execFileSync } = require('node:child_process');
const PERMISSION_PROFILES = Object.freeze({
issues: Object.freeze({
issues: 'write',
}),
'pull-requests': Object.freeze({
contents: 'read',
pull_requests: 'write',
}),
devflow: Object.freeze({
contents: 'read',
issues: 'write',
pull_requests: 'write',
}),
});
function base64Url(value) {
return Buffer.from(value).toString('base64url');
}
function base64ToBase64Url(value) {
return Buffer.from(value, 'base64').toString('base64url');
}
function createJwtSigningInput(clientId, nowSeconds) {
const header = base64Url(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));
const payload = base64Url(JSON.stringify({
iat: nowSeconds - 60,
exp: nowSeconds + 540,
iss: clientId,
}));
return `${header}.${payload}`;
}
function signJwt(signingInput, config, execute = execFileSync) {
const digest = crypto.createHash('sha256').update(signingInput).digest('base64');
const signature = execute(
'az',
[
'keyvault', 'key', 'sign',
'--subscription', config.azureSubscriptionId,
'--vault-name', config.keyVaultName,
'--name', config.keyName,
'--algorithm', 'RS256',
'--digest', digest,
'--query', 'signature',
'--output', 'tsv',
'--only-show-errors',
],
{ encoding: 'utf8' },
).trim();
if (!signature) {
throw new Error('Key Vault returned an empty signature.');
}
return `${signingInput}.${base64ToBase64Url(signature)}`;
}
async function createInstallationToken(config, dependencies = {}) {
const execute = dependencies.execute ?? execFileSync;
const request = dependencies.fetch ?? fetch;
const nowSeconds = dependencies.nowSeconds ?? Math.floor(Date.now() / 1000);
const repositoryParts = config.targetRepository.split('/');
if (repositoryParts.length !== 2 || repositoryParts.some((part) => part.length === 0)) {
throw new Error('TARGET_REPOSITORY must use the owner/repository format.');
}
if (!Object.hasOwn(PERMISSION_PROFILES, config.permissionProfile)) {
throw new Error('PERMISSION_PROFILE must be issues, pull-requests, or devflow.');
}
const permissions = PERMISSION_PROFILES[config.permissionProfile];
const [, repository] = repositoryParts;
const signingInput = createJwtSigningInput(config.githubAppClientId, nowSeconds);
const jwt = signJwt(signingInput, config, execute);
const response = await request(
`https://api.github.com/app/installations/${config.githubAppInstallationId}/access_tokens`,
{
method: 'POST',
headers: {
Accept: 'application/vnd.github+json',
Authorization: `Bearer ${jwt}`,
'X-GitHub-Api-Version': '2022-11-28',
},
body: JSON.stringify({
repositories: [repository],
permissions,
}),
},
);
if (!response.ok) {
throw new Error(`GitHub installation token request failed with HTTP ${response.status}.`);
}
const result = await response.json();
if (typeof result.token !== 'string' || result.token.length === 0) {
throw new Error('GitHub returned an empty installation token.');
}
return result.token;
}
function readConfig(environment) {
const config = {
azureSubscriptionId: environment.AZURE_SUBSCRIPTION_ID,
keyVaultName: environment.KEY_VAULT_NAME,
keyName: environment.KEY_NAME,
githubAppClientId: environment.GITHUB_APP_CLIENT_ID,
githubAppInstallationId: environment.GITHUB_APP_INSTALLATION_ID,
targetRepository: environment.TARGET_REPOSITORY,
permissionProfile: environment.PERMISSION_PROFILE,
};
if (Object.values(config).some((value) => !value)) {
throw new Error('Required GitHub App authentication configuration is missing.');
}
return config;
}
async function main() {
try {
const token = await createInstallationToken(readConfig(process.env));
process.stdout.write(token);
} catch {
console.error('GitHub App token generation failed.');
process.exitCode = 1;
}
}
if (require.main === module) {
void main();
}
module.exports = {
base64ToBase64Url,
createInstallationToken,
createJwtSigningInput,
readConfig,
signJwt,
PERMISSION_PROFILES,
};
+2
View File
@@ -42,3 +42,5 @@ updates:
schedule:
interval: "weekly"
day: "tuesday"
cooldown:
default-days: 7
+30 -17
View File
@@ -1,43 +1,56 @@
# Add 'kernel' label to any change within Connectors, Extensions, Skills, and tests directories
kernel:
- dotnet/src/Connectors/**/*
- dotnet/src/Extensions/**/*
- dotnet/src/Skills/**/*
- dotnet/src/IntegrationTests/**/*
- dotnet/src/SemanticKernel.UnitTests/**/*
- changed-files:
- any-glob-to-any-file:
- dotnet/src/Connectors/**/*
- dotnet/src/Extensions/**/*
- dotnet/src/Skills/**/*
- dotnet/src/IntegrationTests/**/*
- dotnet/src/SemanticKernel.UnitTests/**/*
# Add 'kernel.core' label to any change within the 'SemanticKernel', 'SemanticKernel.Abstractions', or 'SemanticKernel.MetaPackage' directories
kernel.core:
- dotnet/src/SemanticKernel/**/*
- dotnet/src/SemanticKernel.Abstractions/**/*
- dotnet/src/SemanticKernel.MetaPackage/**/*
- changed-files:
- any-glob-to-any-file:
- dotnet/src/SemanticKernel/**/*
- dotnet/src/SemanticKernel.Abstractions/**/*
- dotnet/src/SemanticKernel.MetaPackage/**/*
# Add 'python' label to any change within the 'python' directory
python:
- python/**/*
- changed-files:
- any-glob-to-any-file: python/**/*
# Add 'java' label to any change within the 'java' directory
java:
- java/**/*
- changed-files:
- any-glob-to-any-file: java/**/*
# Add 'samples' label to any change within the 'samples' directory
samples:
- samples/**/*
- changed-files:
- any-glob-to-any-file: samples/**/*
# Add '.NET' label to any change within samples or kernel 'dotnet' directories.
.NET:
- dotnet/**/*
- changed-files:
- any-glob-to-any-file: dotnet/**/*
# Add 'copilot chat' label to any change within the 'samples/apps/copilot-chat-app' directory
copilot chat:
- samples/apps/copilot-chat-app/**/*
- changed-files:
- any-glob-to-any-file: samples/apps/copilot-chat-app/**/*
# Add 'documentation' label to any change within the 'docs' directory, or any '.md' files
documentation:
- docs/**/*
- '**/*.md'
- changed-files:
- any-glob-to-any-file:
- docs/**/*
- '**/*.md'
# Add 'memory' label to any memory connectors in dotnet/ or python/
memory:
- dotnet/src/Connectors/Connectors.Memory.*/**/*
- python/semantic_kernel/connectors/memory/**/*
- changed-files:
- any-glob-to-any-file:
- dotnet/src/Connectors/Connectors.Memory.*/**/*
- python/semantic_kernel/connectors/memory/**/*
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const {
base64ToBase64Url,
createInstallationToken,
createJwtSigningInput,
readConfig,
} = require('../actions/github-app-token/create-token.js');
const CONFIG = {
azureSubscriptionId: 'subscription-id',
keyVaultName: 'vault-name',
keyName: 'key-name',
githubAppClientId: 'client-id',
githubAppInstallationId: '12345',
targetRepository: 'microsoft/semantic-kernel',
permissionProfile: 'devflow',
};
describe('GitHub App token creation', () => {
it('creates a short-lived GitHub App JWT', () => {
const signingInput = createJwtSigningInput('client-id', 1_000);
const [encodedHeader, encodedPayload] = signingInput.split('.');
const header = JSON.parse(Buffer.from(encodedHeader, 'base64url').toString());
const payload = JSON.parse(Buffer.from(encodedPayload, 'base64url').toString());
assert.deepEqual(header, { alg: 'RS256', typ: 'JWT' });
assert.deepEqual(payload, { iat: 940, exp: 1_540, iss: 'client-id' });
});
it('converts Key Vault signatures to unpadded base64url', () => {
assert.equal(base64ToBase64Url('+/8='), '-_8');
});
it('requests a repository-scoped installation token', async () => {
let request;
const token = await createInstallationToken(CONFIG, {
nowSeconds: 1_000,
execute: (command, args) => {
assert.equal(command, 'az');
assert.ok(args.includes('RS256'));
return '+/8=\n';
},
fetch: async (url, options) => {
request = { url, options };
return {
ok: true,
json: async () => ({ token: 'installation-token' }),
};
},
});
assert.equal(token, 'installation-token');
assert.equal(request.url, 'https://api.github.com/app/installations/12345/access_tokens');
assert.match(request.options.headers.Authorization, /^Bearer [^.]+\.[^.]+\.-_8$/);
assert.deepEqual(JSON.parse(request.options.body), {
repositories: ['semantic-kernel'],
permissions: {
contents: 'read',
issues: 'write',
pull_requests: 'write',
},
});
});
it('limits issue-label tokens to issue writes', async () => {
let request;
await createInstallationToken(
{ ...CONFIG, permissionProfile: 'issues' },
{
execute: () => '+/8=\n',
fetch: async (_url, options) => {
request = options;
return {
ok: true,
json: async () => ({ token: 'installation-token' }),
};
},
},
);
assert.deepEqual(JSON.parse(request.body).permissions, {
issues: 'write',
});
});
it('limits pull-request label tokens to contents and pull requests', async () => {
let request;
await createInstallationToken(
{ ...CONFIG, permissionProfile: 'pull-requests' },
{
execute: () => '+/8=\n',
fetch: async (_url, options) => {
request = options;
return {
ok: true,
json: async () => ({ token: 'installation-token' }),
};
},
},
);
assert.deepEqual(JSON.parse(request.body).permissions, {
contents: 'read',
pull_requests: 'write',
});
});
it('rejects unknown permission profiles before signing', async () => {
let signed = false;
await assert.rejects(
createInstallationToken(
{ ...CONFIG, permissionProfile: 'everything' },
{
execute: () => {
signed = true;
return '+/8=\n';
},
},
),
/PERMISSION_PROFILE must be issues, pull-requests, or devflow/,
);
assert.equal(signed, false);
});
it('rejects inherited object properties as permission profiles before signing', async () => {
let signed = false;
await assert.rejects(
createInstallationToken(
{ ...CONFIG, permissionProfile: 'toString' },
{
execute: () => {
signed = true;
return '+/8=\n';
},
},
),
/PERMISSION_PROFILE must be issues, pull-requests, or devflow/,
);
assert.equal(signed, false);
});
it('rejects incomplete configuration', () => {
assert.throws(
() => readConfig({}),
/Required GitHub App authentication configuration is missing/,
);
});
it('rejects repository values with extra path segments before signing', async () => {
let signed = false;
await assert.rejects(
createInstallationToken(
{ ...CONFIG, targetRepository: 'microsoft/semantic-kernel/extra' },
{
execute: () => {
signed = true;
return '+/8=\n';
},
},
),
/TARGET_REPOSITORY must use the owner\/repository format/,
);
assert.equal(signed, false);
});
it('rejects an empty Key Vault signature', async () => {
await assert.rejects(
createInstallationToken(CONFIG, {
execute: () => '\n',
}),
/Key Vault returned an empty signature/,
);
});
it('rejects a failed GitHub token request', async () => {
await assert.rejects(
createInstallationToken(CONFIG, {
execute: () => '+/8=\n',
fetch: async () => ({ ok: false, status: 403 }),
}),
/GitHub installation token request failed with HTTP 403/,
);
});
it('rejects an empty GitHub installation token', async () => {
await assert.rejects(
createInstallationToken(CONFIG, {
execute: () => '+/8=\n',
fetch: async () => ({
ok: true,
json: async () => ({ token: '' }),
}),
}),
/GitHub returned an empty installation token/,
);
});
});
@@ -1,4 +1,4 @@
# Instructions for migrating from Semantic Kernel Agents to Agent Framework in .NET projects.
# Instructions for migrating from Semantic Kernel Agents to Agent Framework in .NET projects.
## Scope
@@ -22,13 +22,13 @@ For each project that needs to be migrated, you need to do the following:
solution or you could not find the project, notify user and continue with other projects).
- Identify the specific Semantic Kernel agent types being used:
- `ChatCompletionAgent` → `ChatClientAgent`
- `OpenAIAssistantAgent` → `assistantsClient.CreateAIAgent()` (via OpenAI Assistants client extension)
- `AzureAIAgent` → `persistentAgentsClient.CreateAIAgent()` (via Azure AI Foundry client extension)
- `OpenAIResponseAgent` → `responsesClient.CreateAIAgent()` (via OpenAI Responses client extension)
- `OpenAIAssistantAgent` → `assistantsClient.AsAIAgent()` (via OpenAI Assistants client extension)
- `AzureAIAgent` → `persistentAgentsClient.AsAIAgent()` (via Azure AI Foundry client extension)
- `OpenAIResponseAgent` → `responsesClient.AsAIAgent()` (via OpenAI Responses client extension)
- `A2AAgent` → `AIAgent` (via A2A card resolver)
- `BedrockAgent` → Custom implementation required (not supported)
- Determine if agents are being created new or retrieved from hosted services:
- **New agents**: Use `CreateAIAgent()` methods
- **New agents**: Use `AsAIAgent()` methods
- **Existing hosted agents**: Use `GetAIAgent(agentId)` methods for OpenAI Assistants and Azure AI Foundry
</agent_type_identification>
@@ -105,8 +105,8 @@ After completing migration, verify these specific items:
1. **Compilation**: Execute `dotnet build` on all modified projects - zero errors required
2. **Namespace Updates**: Confirm all `using Microsoft.SemanticKernel.Agents` statements are replaced
3. **Method Calls**: Verify all `InvokeAsync` calls are changed to `RunAsync`
4. **Return Types**: Confirm handling of `AgentRunResponse` instead of `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>`
5. **Thread Creation**: Validate all thread creation uses `agent.GetNewThread()` pattern
4. **Return Types**: Confirm handling of `AgentResponse` instead of `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>`
5. **Thread Creation**: Validate all thread creation uses `agent.CreateSessionAsync()` pattern
6. **Tool Registration**: Ensure `[KernelFunction]` attributes are removed and `AIFunctionFactory.Create()` is used
7. **Options Configuration**: Verify `AgentRunOptions` or `ChatClientAgentRunOptions` replaces `AgentInvokeOptions`
8. **Breaking Glass**: Test `RawRepresentation` access replaces `InnerContent` access
@@ -119,8 +119,8 @@ Agent Framework provides functionality for creating and managing AI agents throu
Key API differences:
- Agent creation: Remove Kernel dependency, use direct client-based creation
- Method names: `InvokeAsync` → `RunAsync`, `InvokeStreamingAsync` → `RunStreamingAsync`
- Return types: `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` → `AgentRunResponse`
- Thread creation: Provider-specific constructors → `agent.GetNewThread()`
- Return types: `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` → `AgentResponse`
- Thread creation: Provider-specific constructors → `agent.CreateSessionAsync()`
- Tool registration: `KernelPlugin` system → Direct `AIFunction` registration
- Options: `AgentInvokeOptions` → Provider-specific run options (e.g., `ChatClientAgentRunOptions`)
</api_changes>
@@ -142,14 +142,14 @@ Replace these Semantic Kernel agent classes with their Agent Framework equivalen
|----------------------|----------------------------|-------------------|
| `IChatCompletionService` | `IChatClient` | Convert to `IChatClient` using `chatService.AsChatClient()` extensions |
| `ChatCompletionAgent` | `ChatClientAgent` | Remove `Kernel` parameter, add `IChatClient` parameter |
| `OpenAIAssistantAgent` | `AIAgent` (via extension) | **New**: `OpenAIClient.GetAssistantClient().CreateAIAgent()` <br> **Existing**: `OpenAIClient.GetAssistantClient().GetAIAgent(assistantId)` |
| `AzureAIAgent` | `AIAgent` (via extension) | **New**: `PersistentAgentsClient.CreateAIAgent()` <br> **Existing**: `PersistentAgentsClient.GetAIAgent(agentId)` |
| `OpenAIResponseAgent` | `AIAgent` (via extension) | Replace with `OpenAIClient.GetOpenAIResponseClient().CreateAIAgent()` |
| `OpenAIAssistantAgent` | `AIAgent` (via extension) | **New**: `OpenAIClient.GetAssistantClient().AsAIAgent()` <br> **Existing**: `OpenAIClient.GetAssistantClient().GetAIAgent(assistantId)` |
| `AzureAIAgent` | `AIAgent` (via extension) | **New**: `PersistentAgentsClient.AsAIAgent()` <br> **Existing**: `PersistentAgentsClient.GetAIAgent(agentId)` |
| `OpenAIResponseAgent` | `AIAgent` (via extension) | Replace with `OpenAIClient.GetResponsesClient().AsAIAgent()` |
| `A2AAgent` | `AIAgent` (via extension) | Replace with `A2ACardResolver.GetAIAgentAsync()` |
| `BedrockAgent` | Not supported | Custom implementation required |
**Important distinction:**
- **CreateAIAgent()**: Use when creating new agents in the hosted service
- **AsAIAgent()**: Use when creating new agents in the hosted service
- **GetAIAgent(agentId)**: Use when retrieving existing agents from the hosted service
</agent_type_identification>
@@ -158,16 +158,16 @@ Replace these method calls:
| Semantic Kernel Method | Agent Framework Method | Parameter Changes |
|----------------------|----------------------|------------------|
| `agent.InvokeAsync(message, thread, options)` | `agent.RunAsync(message, thread, options)` | Same parameters, different return type |
| `agent.InvokeStreamingAsync(message, thread, options)` | `agent.RunStreamingAsync(message, thread, options)` | Same parameters, different return type |
| `new ChatHistoryAgentThread()` | `agent.GetNewThread()` | No parameters needed |
| `new OpenAIAssistantAgentThread(client)` | `agent.GetNewThread()` | No parameters needed |
| `new AzureAIAgentThread(client)` | `agent.GetNewThread()` | No parameters needed |
| `agent.InvokeAsync(message, thread, options)` | `agent.RunAsync(message, session, options)` | Same parameters, different return type |
| `agent.InvokeStreamingAsync(message, thread, options)` | `agent.RunStreamingAsync(message, session, options)` | Same parameters, different return type |
| `new ChatHistoryAgentThread()` | `await agent.CreateSessionAsync()` | Returns `AgentSession` |
| `new OpenAIAssistantAgentThread(client)` | `await agent.CreateSessionAsync()` | Returns `AgentSession` |
| `new AzureAIAgentThread(client)` | `await agent.CreateSessionAsync()` | Returns `AgentSession` |
| `thread.DeleteAsync()` | Provider-specific cleanup | Use provider client directly |
Return type changes:
- `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` → `AgentRunResponse`
- `IAsyncEnumerable<StreamingChatMessageContent>` → `IAsyncEnumerable<AgentRunResponseUpdate>`
- `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` → `AgentResponse`
- `IAsyncEnumerable<StreamingChatMessageContent>` → `IAsyncEnumerable<AgentResponseUpdate>`
</api_changes>
<configuration_changes>
@@ -191,8 +191,8 @@ Agent Framework changes these behaviors compared to Semantic Kernel Agents:
1. **Thread Management**: Agent Framework automatically manages thread state. Semantic Kernel required manual thread updates in some scenarios (e.g., OpenAI Responses).
2. **Return Types**:
- Non-streaming: Returns single `AgentRunResponse` instead of `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>`
- Streaming: Returns `IAsyncEnumerable<AgentRunResponseUpdate>` instead of `IAsyncEnumerable<StreamingChatMessageContent>`
- Non-streaming: Returns single `AgentResponse` instead of `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>`
- Streaming: Returns `IAsyncEnumerable<AgentResponseUpdate>` instead of `IAsyncEnumerable<StreamingChatMessageContent>`
3. **Tool Registration**: Agent Framework uses direct function registration without requiring `[KernelFunction]` attributes.
@@ -222,6 +222,8 @@ using Microsoft.Extensions.AI;
using Microsoft.Agents.AI;
// Provider-specific namespaces (add only if needed):
using OpenAI; // For OpenAI provider
using OpenAI.Chat; // For ChatClient.AsAIAgent() extension
using OpenAI.Responses; // For ResponsesClient.AsAIAgent() extension
using Azure.AI.OpenAI; // For Azure OpenAI provider
using Azure.AI.Agents.Persistent; // For Azure AI Foundry provider
using Azure.Identity; // For Azure authentication
@@ -254,7 +256,7 @@ AIAgent agent = new ChatClientAgent(chatClient, instructions: "You are a helpful
// Method 2: Extension method (recommended)
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: "You are a helpful assistant");
.AsAIAgent(instructions: "You are a helpful assistant");
```
</configuration_changes>
@@ -314,7 +316,7 @@ AIAgent agent = new ChatClientAgent(chatClient, instructions: "You are a helpful
// Method 2: Extension method (recommended)
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: "You are a helpful assistant");
.AsAIAgent(instructions: "You are a helpful assistant");
```
**Required changes:**
@@ -338,12 +340,12 @@ AgentThread thread = new AzureAIAgentThread(azureClient);
**With this unified Agent Framework pattern:**
```csharp
// Use this single pattern for all agent types:
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
**Required changes:**
1. Remove all `new [Provider]AgentThread()` constructor calls
2. Replace with `agent.GetNewThread()` method call
2. Replace with `agent.CreateSessionAsync()` method call
3. Remove provider client parameters from thread creation
4. Use the same pattern regardless of agent provider type
</api_changes>
@@ -369,7 +371,7 @@ ChatCompletionAgent agent = new() { Kernel = kernel };
[Description("Get the weather for a location")] // Keep Description attribute
static string GetWeather(string location) => $"Weather in {location}";
AIAgent agent = chatClient.CreateAIAgent(
AIAgent agent = chatClient.AsAIAgent(
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
```
@@ -415,12 +417,12 @@ await foreach (var item in agent.InvokeAsync(userInput, thread)) { ... }
static string GetWeather(string location) => $"Weather in {location}";
// Start with an existing agent
AIAgent existingAgent = chatClient.CreateAIAgent(
AIAgent existingAgent = chatClient.AsAIAgent(
instructions: "You are a helpful assistant");
// Create an augmented agent with additional tools using builder middleware
var augmentedAgent = existingAgent.AsBuilder()
.Use(async (chatMessages, agentThread, agentRunOptions, next, cancellationToken) =>
.Use(async (chatMessages, agentSession, agentRunOptions, next, cancellationToken) =>
{
if (agentRunOptions is ChatClientAgentRunOptions chatClientAgentRunOptions)
{
@@ -429,12 +431,12 @@ var augmentedAgent = existingAgent.AsBuilder()
chatClientAgentRunOptions.ChatOptions.Tools.Add(AIFunctionFactory.Create(GetWeather));
}
return await next(chatMessages, agentThread, agentRunOptions, cancellationToken);
return await next(chatMessages, agentSession, agentRunOptions, cancellationToken);
})
.Build();
// Use the augmented agent with the additional tools
AgentRunResponse result = await augmentedAgent.RunAsync(userInput, thread);
AgentResponse result = await augmentedAgent.RunAsync(userInput, session);
```
**Required changes:**
@@ -464,7 +466,7 @@ await foreach (AgentResponseItem<ChatMessageContent> item in agent.InvokeAsync(u
**With this Agent Framework non-streaming pattern:**
```csharp
AgentRunResponse result = await agent.RunAsync(userInput, thread, options);
AgentResponse result = await agent.RunAsync(userInput, session, options);
Console.WriteLine(result);
```
@@ -478,7 +480,7 @@ await foreach (StreamingChatMessageContent update in agent.InvokeStreamingAsync(
**With this Agent Framework streaming pattern:**
```csharp
await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(userInput, thread, options))
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(userInput, session, options))
{
Console.Write(update);
}
@@ -487,8 +489,8 @@ await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(userInpu
**Required changes:**
1. Replace `agent.InvokeAsync()` with `agent.RunAsync()`
2. Replace `agent.InvokeStreamingAsync()` with `agent.RunStreamingAsync()`
3. Change return type handling from `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` to `AgentRunResponse`
4. Change streaming type from `StreamingChatMessageContent` to `AgentRunResponseUpdate`
3. Change return type handling from `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` to `AgentResponse`
4. Change streaming type from `StreamingChatMessageContent` to `AgentResponseUpdate`
5. Remove `await foreach` for non-streaming calls
6. Access message content directly from result object instead of iterating
</api_changes>
@@ -537,7 +539,7 @@ services.AddTransient<ChatCompletionAgent>(sp => new()
services.AddTransient<AIAgent>(sp =>
new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: "You are helpful"));
.AsAIAgent(instructions: "You are helpful"));
```
**Required changes:**
@@ -564,11 +566,11 @@ For every thread created if there's intent to cleanup, the caller should track a
```csharp
// For OpenAI Assistants (when cleanup is needed):
var assistantClient = new OpenAIClient(apiKey).GetAssistantClient();
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteThreadAsync(session.ConversationId);
// For Azure AI Foundry (when cleanup is needed):
var persistentClient = new PersistentAgentsClient(endpoint, credential);
await persistentClient.Threads.DeleteThreadAsync(thread.ConversationId);
await persistentClient.Threads.DeleteThreadAsync(session.ConversationId);
// No thread and agent cleanup is needed for non-hosted agent providers like
// - Azure OpenAI Chat Completion
@@ -580,7 +582,7 @@ await persistentClient.Threads.DeleteThreadAsync(thread.ConversationId);
**Required changes:**
1. Remove `thread.DeleteAsync()` calls
2. Use provider-specific client for cleanup when required
3. Access thread ID via `thread.ConversationId` property
3. Access thread ID via `session.ConversationId` property
4. Only implement cleanup for providers that require it (Assistants, Azure AI Foundry)
</api_changes>
@@ -593,14 +595,14 @@ Use these exact patterns for each provider:
```csharp
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: instructions);
.AsAIAgent(instructions: instructions);
```
**OpenAI Assistants (New):**
```csharp
AIAgent agent = new OpenAIClient(apiKey)
.GetAssistantClient()
.CreateAIAgent(modelId, instructions: instructions);
.AsAIAgent(modelId, instructions: instructions);
```
**OpenAI Assistants (Existing):**
@@ -614,13 +616,13 @@ AIAgent agent = new OpenAIClient(apiKey)
```csharp
AIAgent agent = new AzureOpenAIClient(endpoint, credential)
.GetChatClient(deploymentName)
.CreateAIAgent(instructions: instructions);
.AsAIAgent(instructions: instructions);
```
**Azure AI Foundry (New):**
```csharp
AIAgent agent = new PersistentAgentsClient(endpoint, credential)
.CreateAIAgent(model: deploymentName, instructions: instructions);
.AsAIAgent(model: deploymentName, instructions: instructions);
```
**Azure AI Foundry (Existing):**
@@ -665,9 +667,9 @@ using OpenAI;
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: "You are helpful");
.AsAIAgent(instructions: "You are helpful");
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
</configuration_changes>
@@ -691,7 +693,7 @@ kernel.Plugins.Add(plugin);
static string GetWeather([Description("Location")] string location)
=> $"Weather in {location}";
AIAgent agent = chatClient.CreateAIAgent(
AIAgent agent = chatClient.AsAIAgent(
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
```
@@ -714,7 +716,7 @@ await foreach (var result in agent.InvokeAsync(input, thread, options))
```csharp
ChatClientAgentRunOptions options = new(new ChatOptions { MaxOutputTokens = 1000 });
AgentRunResponse result = await agent.RunAsync(input, thread, options);
AgentResponse result = await agent.RunAsync(input, session, options);
Console.WriteLine(result);
// Access underlying content when needed:
@@ -742,7 +744,7 @@ await foreach (var result in agent.InvokeAsync(input, thread, options))
**With this Agent Framework non-streaming usage pattern:**
```csharp
AgentRunResponse result = await agent.RunAsync(input, thread, options);
AgentResponse result = await agent.RunAsync(input, session, options);
Console.WriteLine($"Tokens: {result.Usage.TotalTokenCount}");
```
@@ -762,7 +764,7 @@ await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsyn
**With this Agent Framework streaming usage pattern:**
```csharp
await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(input, thread, options))
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, session, options))
{
if (update.Contents.OfType<UsageContent>().FirstOrDefault() is { } usageContent)
{
@@ -787,7 +789,7 @@ await foreach (var content in agent.InvokeAsync(userInput, thread))
**With this Agent Framework breaking glass pattern:**
```csharp
var agentRunResponse = await agent.RunAsync(userInput, thread);
var agentRunResponse = await agent.RunAsync(userInput, session);
// If the agent uses a ChatClient the first breaking glass probably will be a Microsoft.Extensions.AI.ChatResponse
ChatResponse? chatResponse = agentRunResponse.RawRepresentation as ChatResponse;
@@ -829,7 +831,7 @@ await foreach (var content in agent.InvokeAsync(userInput, thread))
**With this Agent Framework CodeInterpreter pattern:**
```csharp
var result = await agent.RunAsync(userInput, thread);
var result = await agent.RunAsync(userInput, session);
Console.WriteLine(result);
// Extract chat response MEAI type via first level breaking glass
@@ -919,7 +921,7 @@ var openAIResponse = chatCompletion.GetRawResponse();
**Issue: Thread Type Mismatches**
- **Problem**: Provider-specific thread constructors not found
- **Solution**: Replace all thread constructors with `agent.GetNewThread()`
- **Solution**: Replace all thread constructors with `agent.CreateSessionAsync()`
**Issue: Options Configuration**
- **Problem**: `AgentInvokeOptions` type not found
@@ -937,7 +939,7 @@ var openAIResponse = chatCompletion.GetRawResponse();
2. **Update Namespaces**: Replace SK namespaces with AF namespaces
3. **Update Agent Creation**: Remove Kernel, use direct client creation
4. **Update Method Calls**: Replace `InvokeAsync` with `RunAsync`
5. **Update Thread Creation**: Replace provider-specific constructors with `GetNewThread()`
5. **Update Thread Creation**: Replace provider-specific constructors with `await agent.CreateSessionAsync()`
6. **Update Tool Registration**: Remove attributes, use `AIFunctionFactory.Create()`
7. **Update Options**: Replace `AgentInvokeOptions` with provider-specific options
8. **Test and Validate**: Compile and test all functionality
@@ -988,9 +990,9 @@ using OpenAI;
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: "You are a helpful assistant");
.AsAIAgent(instructions: "You are a helpful assistant");
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
### 2. Azure OpenAI Chat Completion Migration
@@ -1038,7 +1040,7 @@ using Azure.Identity;
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(instructions: "You are a helpful assistant");
.AsAIAgent(instructions: "You are a helpful assistant");
```
### 3. OpenAI Assistants Migration
@@ -1083,12 +1085,12 @@ using OpenAI;
AIAgent agent = new OpenAIClient(apiKey)
.GetAssistantClient()
.CreateAIAgent(modelId, instructions: "You are a helpful assistant");
.AsAIAgent(modelId, instructions: "You are a helpful assistant");
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
// Cleanup when needed
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteThreadAsync(session.ConversationId);
```
**Retrieving an existing assistant:**
@@ -1100,7 +1102,7 @@ AIAgent agent = new OpenAIClient(apiKey)
.GetAssistantClient()
.GetAIAgent(assistantId); // Use existing assistant ID
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
</api_changes>
@@ -1163,12 +1165,12 @@ using Azure.Identity;
var client = new PersistentAgentsClient(endpoint, new AzureCliCredential());
// Create a new AIAgent using Agent Framework
AIAgent agent = client.CreateAIAgent(
AIAgent agent = client.AsAIAgent(
model: deploymentName,
instructions: "You are a helpful assistant",
tools: [/* List of specialized Azure.AI.Agents.Persistent.ToolDefinition types */]);
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
**Retrieving an existing agent:**
@@ -1182,7 +1184,7 @@ var client = new PersistentAgentsClient(endpoint, new AzureCliCredential());
// Retrieve an existing AIAgent using its ID
AIAgent agent = await client.GetAIAgentAsync(agentId);
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
```
</api_changes>
@@ -1269,20 +1271,21 @@ await foreach (AgentResponseItem<ChatMessageContent> responseItem in responseIte
Agent Framework automatically manages the thread, so there's no need to manually update it.
```csharp
using Microsoft.Agents.AI.OpenAI;
using OpenAI.Chat; // For ChatClient.AsAIAgent()
using OpenAI.Responses; // For ResponsesClient.AsAIAgent()
AIAgent agent = new OpenAIClient(apiKey)
.GetOpenAIResponseClient(modelId)
.CreateAIAgent(
.GetResponsesClient(modelId)
.AsAIAgent(
name: "ResponseAgent",
instructions: "Answer all queries in English and French.",
tools: [/* AITools */]);
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, thread);
var result = await agent.RunAsync(userInput, session);
// The thread will be automatically updated with the new response id from this point
// The session will be automatically updated with the new response id from this point
```
</api_changes>
@@ -1336,21 +1339,22 @@ await foreach (AgentResponseItem<ChatMessageContent> responseItem in responseIte
Agent Framework automatically manages the thread, so there's no need to manually update it.
```csharp
using Microsoft.Agents.AI.OpenAI;
using OpenAI.Chat; // For ChatClient.AsAIAgent()
using OpenAI.Responses; // For ResponsesClient.AsAIAgent()
using Azure.AI.OpenAI;
AIAgent agent = new AzureOpenAIClient(endpoint, new AzureCliCredential())
.GetOpenAIResponseClient(modelId)
.CreateAIAgent(
.GetResponsesClient(modelId)
.AsAIAgent(
name: "ResponseAgent",
instructions: "Answer all queries in English and French.",
tools: [/* AITools */]);
AgentThread thread = agent.GetNewThread();
AgentSession session = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, thread);
var result = await agent.RunAsync(userInput, session);
// The thread will be automatically updated with the new response id from this point
// The session will be automatically updated with the new response id from this point
```
</api_changes>
@@ -1513,7 +1517,7 @@ AITool[] tools =
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(
.AsAIAgent(
instructions: "You are a weather assistant",
tools: tools);
```
@@ -1562,10 +1566,10 @@ var renderedTemplate = await new KernelPromptTemplateFactory()
AIAgent agent = new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(instructions: renderedTemplate);
.AsAIAgent(instructions: renderedTemplate);
// No template variables in invocation - use plain string
var result = await agent.RunAsync("What's the weather?", thread);
var result = await agent.RunAsync("What's the weather?");
Console.WriteLine(result);
```
</behavioral_changes>
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
- uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0
with:
days-before-issue-stale: 90
days-before-issue-close: 14
+4 -4
View File
@@ -32,13 +32,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@f3712979fa5f215279b101dd0a2e3bdfb4353324 # v3.37.7
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -52,7 +52,7 @@ jobs:
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
if: ${{ matrix.language != 'java' }}
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@f3712979fa5f215279b101dd0a2e3bdfb4353324 # v3.37.7
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -65,6 +65,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@f3712979fa5f215279b101dd0a2e3bdfb4353324 # v3.37.7
with:
category: "/language:${{matrix.language}}"
+38 -10
View File
@@ -15,8 +15,8 @@ on:
permissions:
contents: read
issues: write
pull-requests: write
copilot-requests: write
id-token: write
concurrency:
group: devflow-pr-review-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
@@ -27,14 +27,40 @@ env:
DEVFLOW_REF: main
TARGET_REPO_PATH: ${{ github.workspace }}/target-repo
DEVFLOW_PATH: ${{ github.workspace }}/devflow
MODEL_CONFIG_PATH: ${{ github.workspace }}/devflow/config.ci.yaml
jobs:
review:
runs-on: ubuntu-latest
environment: github-app-auth
timeout-minutes: 60
if: ${{ github.event_name != 'pull_request_target' || !github.event.pull_request.draft }}
steps:
- name: Checkout GitHub automation
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.base.sha || github.sha }}
sparse-checkout: .github/actions/github-app-token
fetch-depth: 1
persist-credentials: false
- name: Get GitHub automation token
id: github-auth
uses: ./.github/actions/github-app-token
with:
mode: ${{ vars.GH_APP_AUTH_MODE }}
azure-client-id: ${{ secrets.GH_APP_AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.GH_APP_AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.GH_APP_AZURE_SUBSCRIPTION_ID }}
key-vault-name: ${{ secrets.GH_APP_KEY_VAULT_NAME }}
key-name: ${{ secrets.GH_APP_KEY_NAME }}
github-app-client-id: ${{ secrets.GH_APP_CLIENT_ID }}
github-app-installation-id: ${{ secrets.GH_APP_INSTALLATION_ID }}
repository: ${{ github.repository }}
permission-profile: devflow
fallback-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
- name: Resolve PR metadata
id: pr
shell: bash
@@ -64,7 +90,7 @@ jobs:
# Safe checkout: base repo only, not the untrusted PR head.
- name: Checkout target repo base
uses: actions/checkout@v5
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.base.sha || github.sha }}
fetch-depth: 0
@@ -73,7 +99,7 @@ jobs:
# Private DevFlow checkout: the PAT/token grants access to this repo's code.
- name: Checkout DevFlow
uses: actions/checkout@v5
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ env.DEVFLOW_REPOSITORY }}
ref: ${{ env.DEVFLOW_REF }}
@@ -83,12 +109,12 @@ jobs:
path: devflow
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.13"
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -101,8 +127,8 @@ jobs:
id: spam
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
DEVFLOW_GITHUB_TOKEN: ${{ steps.github-auth.outputs.token }}
GITHUB_TOKEN: ${{ github.token }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
PR_REPO: ${{ steps.pr.outputs.repo }}
@@ -112,6 +138,7 @@ jobs:
--repo "$PR_REPO" \
--pr-number "$PR_NUMBER" \
--repo-path "${TARGET_REPO_PATH}" \
--github-token "$DEVFLOW_GITHUB_TOKEN" \
--apply-labels
- name: Stop after spam gate
@@ -127,8 +154,8 @@ jobs:
id: review
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
DEVFLOW_GITHUB_TOKEN: ${{ steps.github-auth.outputs.token }}
GITHUB_TOKEN: ${{ github.token }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
PR_URL: ${{ steps.pr.outputs.pr_url }}
@@ -136,4 +163,5 @@ jobs:
uv run python scripts/trigger_pr_review.py \
--pr-url "$PR_URL" \
--github-username "$GITHUB_ACTOR" \
--github-token "$DEVFLOW_GITHUB_TOKEN" \
--no-require-comment-selection
+12 -12
View File
@@ -29,10 +29,10 @@ jobs:
outputs:
dotnetChanges: ${{ steps.filter.outputs.dotnet }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: dorny/paths-filter@v2
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter
with:
filters: |
@@ -69,19 +69,19 @@ jobs:
runs-on: ${{ matrix.os }}
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup dotnet
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0
with:
global-json-file: ${{ github.workspace }}/dotnet/global.json
- name: Build dotnet solutions
shell: bash
run: |
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ')
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | grep -v "MEVD.slnx" | tr '\n' ' ')
for solution in $SOLUTIONS; do
dotnet build $solution -c ${{ matrix.configuration }} --warnaserror
done
@@ -89,7 +89,7 @@ jobs:
- name: Package install check
shell: bash
run: |
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ')
export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | grep -v "MEVD.slnx" | tr '\n' ' ')
for solution in $SOLUTIONS; do
dotnet pack $solution -c ${{ matrix.configuration }} --no-build --no-restore --output ./artifacts
done
@@ -115,7 +115,7 @@ jobs:
- name: Run Unit Tests
shell: bash
run: |
export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | grep -v -E "(Experimental.Orchestration.Flow.UnitTests.csproj|Experimental.Assistants.UnitTests.csproj)" | tr '\n' ' ')
export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | grep -v -E "(Experimental.Orchestration.Flow.UnitTests.csproj|Experimental.Assistants.UnitTests.csproj)" | grep -v "test/VectorData/" | tr '\n' ' ')
for project in $UT_PROJECTS; do
dotnet test -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --collect:"XPlat Code Coverage" --results-directory:"TestResults/Coverage/" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByAttribute=GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute
done
@@ -126,7 +126,7 @@ jobs:
- name: Azure CLI Login
if: github.event_name != 'pull_request' && matrix.integration-tests
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -184,14 +184,14 @@ jobs:
# Generate test reports and check coverage
- name: Generate test reports
uses: danielpalme/[email protected]2
uses: danielpalme/ReportGenerator-GitHub-Action@18e0cd4c1bebd0c8b3978b380a6a4ea61c51178e # 5.4.15
with:
reports: "./TestResults/Coverage/**/coverage.cobertura.xml"
targetdir: "./TestResults/Reports"
reporttypes: "HtmlInline;JsonSummary"
- name: Upload coverage report artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: CoverageReport-${{ matrix.os }}-${{ matrix.dotnet }}-${{ matrix.configuration }} # Artifact name
path: ./TestResults/Reports # Directory containing files to upload
@@ -232,13 +232,13 @@ jobs:
- name: Fail workflow if tests failed
id: check_tests_failed
if: contains(join(needs.*.result, ','), 'failure')
uses: actions/github-script@v6
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setFailed('Integration Tests Failed!')
- name: Fail workflow if tests cancelled
id: check_tests_cancelled
if: contains(join(needs.*.result, ','), 'cancelled')
uses: actions/github-script@v6
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setFailed('Integration Tests Cancelled!')
+6 -6
View File
@@ -24,7 +24,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
clean: true
persist-credentials: false
@@ -55,7 +55,7 @@ jobs:
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
@@ -72,19 +72,19 @@ jobs:
env:
NUGET_CERT_REVOCATION_MODE: offline
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
clean: true
persist-credentials: false
- name: Setup .NET SDK ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0
with:
dotnet-version: ${{ matrix.dotnet-version }}
env:
NUGET_AUTH_TOKEN: ${{ secrets.GPR_READ_TOKEN }}
- uses: actions/cache@v4
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.nuget/packages
# Look to see if there is a cache hit for the corresponding requirements file
@@ -122,7 +122,7 @@ jobs:
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
+13 -6
View File
@@ -33,7 +33,7 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
@@ -41,7 +41,7 @@ jobs:
- name: Get changed files
id: changed-files
if: github.event_name == 'pull_request'
uses: jitterbit/get-changed-files@v1
uses: jitterbit/get-changed-files@b17fbb00bdc0c0f63fcf166580804b4d2cdc2a42 # v1
continue-on-error: true
- name: No C# files changed
@@ -53,11 +53,14 @@ jobs:
- name: Find csproj files
id: find-csproj
if: github.event_name != 'pull_request' || steps.changed-files.outputs.added_modified != '' || steps.changed-files.outcome == 'failure'
env:
ADDED_MODIFIED: ${{ steps.changed-files.outputs.added_modified }}
run: |
csproj_files=()
exclude_files=("Experimental.Orchestration.Flow.csproj" "Experimental.Orchestration.Flow.UnitTests.csproj" "Experimental.Orchestration.Flow.IntegrationTests.csproj")
set -f
if [[ ${{ steps.changed-files.outcome }} == 'success' ]]; then
for file in ${{ steps.changed-files.outputs.added_modified }}; do
for file in $ADDED_MODIFIED; do
echo "$file was changed"
dir="./$file"
while [[ $dir != "." && $dir != "/" && $dir != $GITHUB_WORKSPACE ]]; do
@@ -78,7 +81,8 @@ jobs:
fi
csproj_files=($(printf "%s\n" "${csproj_files[@]}" | sort -u))
echo "Found ${#csproj_files[@]} unique csproj/slnx files: ${csproj_files[*]}"
echo "::set-output name=csproj_files::${csproj_files[*]}"
echo "csproj_files=${csproj_files[*]}" >> "$GITHUB_OUTPUT"
set +f
- name: Pull container dotnet/sdk:${{ matrix.dotnet }}
if: steps.find-csproj.outputs.csproj_files != ''
@@ -87,8 +91,11 @@ jobs:
# This step will run dotnet format on each of the unique csproj files and fail if any changes are made
- name: Run dotnet format
if: steps.find-csproj.outputs.csproj_files != ''
env:
CSPROJ_FILES: ${{ steps.find-csproj.outputs.csproj_files }}
run: |
for csproj in ${{ steps.find-csproj.outputs.csproj_files }}; do
set -f
for csproj in $CSPROJ_FILES; do
echo "Running dotnet format on $csproj"
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }} /bin/sh -c "dotnet format $csproj --verify-no-changes --verbosity diagnostic"
docker run --rm -v "$(pwd):/app" -w /app mcr.microsoft.com/dotnet/sdk:${{ matrix.dotnet }} dotnet format "$csproj" --verify-no-changes --verbosity diagnostic
done
@@ -22,14 +22,14 @@ jobs:
configuration: [Debug]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
if: ${{ github.event_name != 'pull_request' }}
with:
clean: true
persist-credentials: false
- name: Setup .NET
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0
if: ${{ github.event_name != 'pull_request' }}
with:
dotnet-version: 10.0.x
@@ -60,7 +60,7 @@ jobs:
done
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dotnet-testresults-${{ matrix.configuration }}
path: ./TestResults
@@ -0,0 +1,37 @@
name: GitHub automation tests
on:
pull_request:
paths:
- ".github/actions/**"
- ".github/tests/**"
- ".github/workflows/devflow-pr-review.yml"
- ".github/workflows/github-automation-tests.yml"
- ".github/workflows/label-issues.yml"
- ".github/workflows/label-pr.yml"
push:
branches:
- main
paths:
- ".github/actions/**"
- ".github/tests/**"
- ".github/workflows/devflow-pr-review.yml"
- ".github/workflows/github-automation-tests.yml"
- ".github/workflows/label-issues.yml"
- ".github/workflows/label-pr.yml"
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
- name: Run JavaScript tests
run: node --test .github/tests/*.js
+28 -3
View File
@@ -10,12 +10,37 @@ jobs:
name: "Issue: add labels"
if: ${{ github.event.action == 'opened' || github.event.action == 'reopened' }}
runs-on: ubuntu-latest
environment: github-app-auth
permissions:
issues: write
contents: read
id-token: write
steps:
- uses: actions/github-script@v6
- name: Checkout GitHub automation
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
sparse-checkout: .github/actions/github-app-token
fetch-depth: 1
persist-credentials: false
- name: Get GitHub automation token
id: github-auth
uses: ./.github/actions/github-app-token
with:
mode: ${{ vars.GH_APP_AUTH_MODE }}
azure-client-id: ${{ secrets.GH_APP_AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.GH_APP_AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.GH_APP_AZURE_SUBSCRIPTION_ID }}
key-vault-name: ${{ secrets.GH_APP_KEY_VAULT_NAME }}
key-name: ${{ secrets.GH_APP_KEY_NAME }}
github-app-client-id: ${{ secrets.GH_APP_CLIENT_ID }}
github-app-installation-id: ${{ secrets.GH_APP_INSTALLATION_ID }}
repository: ${{ github.repository }}
permission-profile: issues
fallback-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.github-auth.outputs.token }}
script: |
// Get the issue body and title
const body = context.payload.issue.body
+28 -3
View File
@@ -11,11 +11,36 @@ on: [pull_request_target]
jobs:
add_label:
runs-on: ubuntu-latest
environment: github-app-auth
permissions:
contents: read
pull-requests: write
id-token: write
steps:
- uses: actions/labeler@v4
- name: Checkout GitHub automation
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repo-token: "${{ secrets.GH_ACTIONS_PR_WRITE }}"
ref: ${{ github.event.pull_request.base.sha }}
sparse-checkout: .github/actions/github-app-token
fetch-depth: 1
persist-credentials: false
- name: Get GitHub automation token
id: github-auth
uses: ./.github/actions/github-app-token
with:
mode: ${{ vars.GH_APP_AUTH_MODE }}
azure-client-id: ${{ secrets.GH_APP_AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.GH_APP_AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.GH_APP_AZURE_SUBSCRIPTION_ID }}
key-vault-name: ${{ secrets.GH_APP_KEY_VAULT_NAME }}
key-name: ${{ secrets.GH_APP_KEY_NAME }}
github-app-client-id: ${{ secrets.GH_APP_CLIENT_ID }}
github-app-installation-id: ${{ secrets.GH_APP_INSTALLATION_ID }}
repository: ${{ github.repository }}
permission-profile: pull-requests
fallback-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
with:
repo-token: ${{ steps.github-auth.outputs.token }}
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/github-script@v6
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
name: "Issue/PR: update title"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
+2 -2
View File
@@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-22.04
# check out the latest version of the code
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Checks the status of hyperlinks in all files
- name: Run linkspector
uses: umbrelladocs/action-linkspector@v1
uses: umbrelladocs/action-linkspector@568ec8d29fa92b31fd9ea5381e155c51e922af83 # v1.5.5
with:
reporter: local
filter_mode: nofilter
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
# NOTE: v1 is updated to reflect the latest v1.x.y. Please use any tag/branch that suits your needs:
# https://github.com/upsidr/merge-gatekeeper/tags
# https://github.com/upsidr/merge-gatekeeper/branches
uses: upsidr/merge-gatekeeper@v1
uses: upsidr/merge-gatekeeper@09af7a82c1666d0e64d2bd8c01797a0bcfd3bb5d # v1.2.1
if: github.event_name == 'pull_request'
with:
token: ${{ secrets.GITHUB_TOKEN }}
+5 -5
View File
@@ -17,9 +17,9 @@ jobs:
env:
UV_PYTHON: "3.10"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -31,18 +31,18 @@ jobs:
- name: Build the package
run: cd python && make build
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
files: |
python/dist/*
- name: Azure Login
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Start DevOps pipeline
uses: azure/cli@v2
uses: azure/cli@9eb25b8360668fb0ecbafa808d40e2197b2f5f52 # v3.0.0
with:
inlineScript: |
az pipelines run --id ${{ vars.ADO_PYTHON_RELEASE_ID }} --org ${{ vars.ADO_ORG }} --project ${{ vars.ADO_PROJECT_NAME }} --parameters tag=${{ github.event.release.tag_name }} delay=0
+41 -35
View File
@@ -84,8 +84,8 @@ jobs:
outputs:
pythonChanges: ${{ steps.filter.outputs.python}}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter
with:
filters: |
@@ -119,9 +119,9 @@ jobs:
UV_PYTHON: ${{ matrix.python-version }}
COMPLETIONS_CONCEPT_SAMPLE: "true"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -131,21 +131,23 @@ jobs:
run: |
uv sync --all-extras --dev
- name: Google auth
uses: google-github-actions/auth@v3
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
project_id: ${{ vars.VERTEX_AI_PROJECT_ID }}
credentials_json: ${{ secrets.VERTEX_AI_SERVICE_ACCOUNT_KEY }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
# Bedrock tests are disabled while the integration credentials are invalid.
if: false
uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -154,7 +156,7 @@ jobs:
id: run_tests_ai_services
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/completions ./tests/integration/embeddings ./tests/samples ./tests/integration/cross_language
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal -m "not ollama" -k "not bedrock" ./tests/integration/completions ./tests/integration/embeddings ./tests/samples ./tests/integration/cross_language
python-merge-gate-multi-modality:
name: Python Pre-Merge Integration Tests - Multi-Modality
@@ -174,9 +176,9 @@ jobs:
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -186,7 +188,7 @@ jobs:
uv sync --all-extras --dev
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -215,9 +217,9 @@ jobs:
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -226,14 +228,16 @@ jobs:
run: |
uv sync --all-extras --dev
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
# Bedrock tests are disabled while the integration credentials are invalid.
if: false
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -242,7 +246,7 @@ jobs:
id: run_tests_agents
shell: bash
run: |
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal ./tests/integration/agents
uv run pytest -v --log-cli-level=INFO --durations=20 -n logical --dist loadfile --dist worksteal -k "not bedrock" ./tests/integration/agents
python-merge-gate-ollama:
name: Python Pre-Merge Integration Tests - Ollama
@@ -264,9 +268,9 @@ jobs:
UV_PYTHON: ${{ matrix.python-version }}
COMPLETIONS_CONCEPT_SAMPLE: "true"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -329,9 +333,9 @@ jobs:
- 8080:8080
- 50051:50051
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -342,7 +346,7 @@ jobs:
uv sync --all-extras --dev
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -387,9 +391,9 @@ jobs:
- 8080:8080
- 50051:50051
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -415,14 +419,16 @@ jobs:
ollama pull ${{ vars.OLLAMA_EMBEDDING_MODEL_ID }}
ollama list
- name: Google auth
uses: google-github-actions/auth@v3
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
project_id: ${{ vars.VERTEX_AI_PROJECT_ID }}
credentials_json: ${{ secrets.VERTEX_AI_SERVICE_ACCOUNT_KEY }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
# Bedrock tests are disabled while the integration credentials are invalid.
if: false
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -435,7 +441,7 @@ jobs:
Start-CosmosDbEmulator
- name: Azure CLI Login
if: github.event_name != 'pull_request'
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
@@ -446,14 +452,14 @@ jobs:
shell: bash
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, Ollama is disabled for now.
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/completions
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" -k "not bedrock" ./tests/integration/completions
- name: Run Integration Tests - Embeddings
id: run_tests_embeddings
timeout-minutes: 5
shell: bash
# Ollama tests are very unstable at the moment. It often fails to pull models from the Ollama server. Thus, Ollama is disabled for now.
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" ./tests/integration/embeddings
uv run pytest -v -n logical --dist loadfile --dist worksteal -m "not ollama" -k "not bedrock" ./tests/integration/embeddings
- name: Run Integration Tests - Memory
id: run_tests_memory
timeout-minutes: 5
@@ -483,7 +489,7 @@ jobs:
timeout-minutes: 10
shell: bash
run: |
uv run pytest -v -n logical --dist loadfile --dist worksteal ./tests/integration/agents
uv run pytest -v -n logical --dist loadfile --dist worksteal -k "not bedrock" ./tests/integration/agents
- name: Run Integration Tests - Multi-Modality
id: run_tests_multi_modality
timeout-minutes: 5
@@ -534,19 +540,19 @@ jobs:
- name: Fail workflow if tests failed
id: check_tests_failed
if: contains(join(needs.*.result, ','), 'failure')
uses: actions/github-script@v6
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setFailed('Integration Tests Failed!')
- name: Fail workflow if tests cancelled
id: check_tests_cancelled
if: contains(join(needs.*.result, ','), 'cancelled')
uses: actions/github-script@v6
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setFailed('Integration Tests Cancelled!')
- name: Microsoft Teams Notification
uses: skitionek/notify-microsoft-teams@v1.0.9
uses: skitionek/notify-microsoft-teams@216b8b28967e7e89b0b64b81dc94aeae90e642ab # v1.3.0
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
with:
webhook_url: ${{ secrets.MSTEAMS_WEBHOOK }}
@@ -556,7 +562,7 @@ jobs:
title: "{title: ` ${{ env.run_type }}: ${{ env.date }} `, text: ` ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`}"
- name: Microsoft Teams Notification (Dry Run)
uses: skitionek/notify-microsoft-teams@v1.0.9
uses: skitionek/notify-microsoft-teams@216b8b28967e7e89b0b64b81dc94aeae90e642ab # v1.3.0
if: github.ref != 'refs/heads/main'
with:
webhook_url: NONE
+3 -3
View File
@@ -23,9 +23,9 @@ jobs:
UV_CACHE_DIR: /tmp/.uv-cache
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -33,7 +33,7 @@ jobs:
cache-dependency-glob: "**/uv.lock"
- name: Install the project
run: uv sync --all-extras --dev
- uses: pre-commit/[email protected]
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
name: Run Pre-Commit Hooks
with:
extra_args: --config python/.pre-commit-config.yaml --all-files
+2 -2
View File
@@ -18,13 +18,13 @@ jobs:
environment: "integration"
steps:
- name: Azure Login
uses: azure/login@v2
uses: azure/login@7184910d9eb2b1c5e48f7073824a90609bb9b6d6 # v2.3.1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Start DevOps pipeline
uses: azure/cli@v2
uses: azure/cli@9eb25b8360668fb0ecbafa808d40e2197b2f5f52 # v3.0.0
with:
inlineScript: |
az pipelines run --id ${{ vars.ADO_PYTHON_RELEASE_ID }} --org ${{ vars.ADO_ORG }} --project ${{ vars.ADO_PROJECT_NAME }} --parameters tag=${{ inputs.tag }} delay=0
@@ -8,6 +8,7 @@ on:
permissions:
contents: read
actions: read
pull-requests: write
jobs:
@@ -19,11 +20,11 @@ jobs:
run:
working-directory: python
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Download coverage report
uses: actions/download-artifact@v5
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
path: ./python
merge-multiple: true
@@ -35,13 +36,17 @@ jobs:
# The PR number is needed to post the comment on the PR
run: |
PR_NUMBER=$(cat pr_number)
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
echo "::error::PR number file contains invalid content"
exit 1
fi
echo "PR number: $PR_NUMBER"
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
- name: Pytest coverage comment
id: coverageComment
uses: MishaKav/[email protected]
uses: MishaKav/pytest-coverage-comment@1bdbba85fb74a2fdc1ec66383acec1091610f82b # v1.1.57
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
github-token: ${{ github.token }}
issue-number: ${{ env.PR_NUMBER }}
pytest-xml-coverage-path: python/python-coverage.xml
title: "Python Test Coverage Report"
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
env:
UV_PYTHON: "3.10"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# Save the PR number to a file since the workflow_run event
# in the coverage report workflow does not have access to it
- name: Save PR number
run: |
echo ${{ github.event.number }} > ./pr_number
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -38,7 +38,7 @@ jobs:
- name: Test with pytest
run: uv run --frozen pytest -q --junitxml=pytest.xml --cov=semantic_kernel --cov-report=term-missing:skip-covered --cov-report=xml:python-coverage.xml ./tests/unit --ignore=./tests/unit/processes/dapr_runtime
- name: Upload coverage report
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
path: |
python/python-coverage.xml
+3 -3
View File
@@ -39,9 +39,9 @@ jobs:
run:
working-directory: python
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
version: "0.5.x"
enable-cache: true
@@ -65,7 +65,7 @@ jobs:
run: uv run --frozen pytest --junitxml=pytest-dapr.xml ./tests/unit/processes/dapr_runtime
- name: Surface failing tests
if: ${{ !matrix.experimental && matrix.test-suite == 'unit-all-except-dapr' }}
uses: pmeier/pytest-results-action@v0.7.2
uses: pmeier/pytest-results-action@fdc7f18d9934e38aca411ca9557e6577bd25ca9c # v0.9.0
with:
path: python/pytest.xml
summary: true
+10 -2
View File
@@ -20,12 +20,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Get changed files
id: changed-files
if: github.event_name == 'pull_request'
uses: jitterbit/get-changed-files@b17fbb00bdc0c0f63fcf166580804b4d2cdc2a42 # v1
continue-on-error: true
- name: Use custom config file
uses: crate-ci/typos@v1.36.2
uses: crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0
with:
files: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.added_modified || '.' }}
config: .github/_typos.toml
write_changes: false
+2
View File
@@ -502,3 +502,5 @@ swa-cli.config.json
# dapr extension files
**/dapr.yaml
*.lscache
+5 -1
View File
@@ -1,5 +1,10 @@
# Semantic Kernel
> [!IMPORTANT]
> Semantic Kernel is now [Microsoft Agent Framework](https://github.com/microsoft/agent-framework)! Microsoft Agent Framework (MAF) is the enterprise‑ready successor to Semantic Kernel. Microsoft Agent Framework is now available at version 1.0 as a production-ready release: stable APIs, and a commitment to long-term support. Whether you're building a single assistant or orchestrating a fleet of specialized agents, Microsoft Agent Framework 1.0 gives you enterprise-grade multi-agent orchestration, multi-provider model support, and cross-runtime interoperability via A2A and MCP.
>
> Learn more about Semantic Kernel and Agent Framework here: [Semantic Kernel and Microsoft Agent Framework on the Agent Framework blog](https://devblogs.microsoft.com/agent-framework/semantic-kernel-and-microsoft-agent-framework/), and try out the [Semantic Kernel migration guide](https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel).
**Build intelligent AI agents and multi-agent systems with this enterprise-ready orchestration framework**
[![License: MIT](https://img.shields.io/github/license/microsoft/semantic-kernel)](https://github.com/microsoft/semantic-kernel/blob/main/LICENSE)
@@ -7,7 +12,6 @@
[![Nuget package](https://img.shields.io/nuget/vpre/Microsoft.SemanticKernel)](https://www.nuget.org/packages/Microsoft.SemanticKernel/)
[![Discord](https://img.shields.io/discord/1063152441819942922?label=Discord&logo=discord&logoColor=white&color=d82679)](https://aka.ms/SKDiscord)
## What is Semantic Kernel?
Semantic Kernel is a model-agnostic SDK that empowers developers to build, orchestrate, and deploy AI agents and multi-agent systems. Whether you're building a simple chatbot or a complex multi-agent workflow, Semantic Kernel provides the tools you need with enterprise-grade reliability and flexibility.
@@ -144,7 +144,7 @@ Currently the priorities are ordered but not necessarily needs to be implemented
Chosen option: "Feature Branch Strategy", because it allows individual features to be developed in isolation, minimizing conflicts with the main branch and facilitating easier code reviews.
## Fequent Asked Questions
## Frequent Asked Questions
### Is there a migration strategy for initiatives that followed the old contribution way with forks, and now have to switch to branches in microsoft/semantic-kernel?
@@ -151,7 +151,7 @@ public sealed record FunctionView(
| Type | Pros | Cons |
| ------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
| JsonSchema.Net.JsonSchema | Popular and has frequent updates, built on top of System.Net | Takes a dependency on OSS in SK core |
| NJsonShema.JsonSchema | Very popular, frequent updates, long term project | Built on top of Json.Net (Newtonsoft) |
| NJsonSchema.JsonSchema | Very popular, frequent updates, long term project | Built on top of Json.Net (Newtonsoft) |
| JsonDocument | Native C# type, fast and flexible | Not a Json Schema, but a Json DOM container for the schema |
| String | Native C# type | Not a Json Schema or Json DOM, very poor type hinting |
+7 -7
View File
@@ -1,5 +1,5 @@
---
# Reestructure of How Sample Code will be Structured In the Repository
# Restructure of How Sample Code will be Structured In the Repository
status: accepted
contact: rogerbarreto
@@ -228,7 +228,7 @@ Identified Component Oriented Concepts:
- Planners
- Handlerbars
- Handlebars
- Authentication
@@ -358,7 +358,7 @@ Concepts/
│ ├── Resiliency/
│ └── Usage/
├── Planners/
│ └── Handlerbars/
│ └── Handlebars/
├── Authentication/
│ └── Azure AD/
├── Function Calling/
@@ -420,7 +420,7 @@ Concepts/
│ ├── Resiliency/
│ └── Usage/
├── Planners/
│ └── Handlerbars/
│ └── Handlebars/
├── Authentication/
│ └── Azure AD/
├── Function Calling/
@@ -502,7 +502,7 @@ Concepts/
├── DependencyInjection
├── HttpClient.Resiliency
├── HttpClient.Usage
├── Planners.Handlerbars
├── Planners.Handlebars
├── Authentication.AzureAD
├── FunctionCalling.AutoFunctionCalling
├── FunctionCalling.ManualFunctionCalling
@@ -545,7 +545,7 @@ Concepts/
├── Logging
├── DependencyInjection
├── HttpClient
├── Planners.Handlerbars
├── Planners.Handlebars
├── Authentication.AzureAD
├── FunctionCalling
├── Filtering
@@ -634,7 +634,7 @@ Concepts/
Pros:
- Beginers will be oriented to the right difficulty level and examples will be more organized by complexity
- Beginners will be oriented to the right difficulty level and examples will be more organized by complexity
Cons:
+1 -1
View File
@@ -170,7 +170,7 @@ await ragStore.UpsertDocumentsAsync(
var agentThread = new ChatHistoryAgentThread();
agentThread.ThreadExtensionsManager.RegisterThreadExtension(ragComponent);
// Inovke the agent.
// Invoke the agent.
var asyncResults1 = agent.InvokeAsync("What was the income of Contoso for 2023", agentThread);
// Expected response contains the 174M income from the document.
```
+70 -68
View File
@@ -6,27 +6,27 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="9.3.1-preview.1.25305.6" />
<PackageVersion Include="Aspire.Azure.Search.Documents" Version="9.5.1" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.0.0" />
<PackageVersion Include="Aspire.Hosting.Azure.CognitiveServices" Version="13.0.0" />
<PackageVersion Include="Aspire.Azure.Search.Documents" Version="13.4.6" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.4.6" />
<PackageVersion Include="Aspire.Hosting.Azure.CognitiveServices" Version="13.4.6" />
<PackageVersion Include="Aspire.Hosting.NodeJs" Version="9.5.2" />
<PackageVersion Include="CommunityToolkit.Aspire.Hosting.Dapr" Version="9.9.0" />
<PackageVersion Include="CommunityToolkit.Aspire.Hosting.NodeJS.Extensions" Version="9.9.0" />
<PackageVersion Include="Aspire.Hosting.Azure.Search" Version="13.0.0" />
<PackageVersion Include="AWSSDK.BedrockAgent" Version="4.0.7.5" />
<PackageVersion Include="AWSSDK.BedrockAgentRuntime" Version="4.0.8.5" />
<PackageVersion Include="AWSSDK.BedrockRuntime" Version="4.0.14.5" />
<PackageVersion Include="AWSSDK.Core" Version="4.0.3.8" />
<PackageVersion Include="AWSSDK.Extensions.Bedrock.MEAI" Version="4.0.5.3" />
<PackageVersion Include="AWSSDK.Extensions.NETCore.Setup" Version="4.0.3.19" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="4.0.5.6" />
<PackageVersion Include="Aspire.Hosting.Azure.Search" Version="13.4.6" />
<PackageVersion Include="MessagePack" Version="3.1.7" /> <!-- Transitive dependency of Aspire pinned to newer version due to vulnerability in 2.5.192 -->
<PackageVersion Include="AWSSDK.BedrockAgent" Version="4.0.100.8" />
<PackageVersion Include="AWSSDK.BedrockAgentRuntime" Version="4.0.100.7" />
<PackageVersion Include="AWSSDK.BedrockRuntime" Version="4.0.101.1" />
<PackageVersion Include="AWSSDK.Core" Version="4.0.101" />
<PackageVersion Include="AWS.Bedrock.MEAI" Version="1.0.0" />
<PackageVersion Include="AWSSDK.Extensions.NETCore.Setup" Version="4.0.100.7" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="4.0.100.7" />
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.1.0" />
<PackageVersion Include="Azure.AI.ContentSafety" Version="1.0.0" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.9.0-beta.1" />
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0-beta.2" />
<PackageVersion Include="Azure.Identity" Version="1.19.0" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.5.0" />
<PackageVersion Include="Azure.Search.Documents" Version="11.7.0" />
<PackageVersion Include="Azure.AI.Projects" Version="2.0.1" />
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.8.3" />
<PackageVersion Include="Community.OData.Linq" Version="2.1.0" />
<PackageVersion Include="Dapr.Actors" Version="1.16.1" />
<PackageVersion Include="Dapr.Actors.AspNetCore" Version="1.16.1" />
@@ -50,22 +50,24 @@
<PackageVersion Include="JsonSchema.Net" Version="7.3.4" />
<PackageVersion Include="JsonSchema.Net.Generation" Version="5.0.2" />
<PackageVersion Include="Markdig" Version="0.40.0" />
<PackageVersion Include="Microsoft.Agents.AI.Abstractions" Version="1.0.0-preview.251009.1" />
<PackageVersion Include="Microsoft.Agents.AI.OpenAI" Version="1.0.0-preview.251009.1" />
<PackageVersion Include="Microsoft.Agents.AI.AzureAI" Version="1.0.0-preview.251009.1" />
<PackageVersion Include="Microsoft.Agents.AI.Workflows" Version="1.0.0-preview.251009.1" />
<PackageVersion Include="Microsoft.Agents.AI.Abstractions" Version="1.0.0" />
<PackageVersion Include="Microsoft.Agents.AI.Foundry" Version="1.0.0" />
<PackageVersion Include="Microsoft.Agents.AI.OpenAI" Version="1.0.0" />
<PackageVersion Include="Microsoft.Agents.AI.Workflows" Version="1.0.0" />
<PackageVersion Include="Microsoft.Agents.CopilotStudio.Client" Version="1.1.107-beta" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.13" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.14" />
<PackageVersion Include="Microsoft.AspNetCore.OData" Version="9.5.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.30" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.2" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker" Version="2.0.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.3.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.0.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues" Version="5.5.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker.SDK" Version="2.0.0" />
<PackageVersion Include="Microsoft.Azure.Kusto.Data" Version="12.2.8" />
<PackageVersion Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="1.5.1" />
<PackageVersion Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="1.6.0" />
<PackageVersion Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="5.3.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.4" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.6" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageVersion Include="Microsoft.Bcl.Memory" Version="10.0.4" />
<PackageVersion Include="Microsoft.Bcl.Numerics" Version="10.0.2" />
@@ -73,10 +75,11 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
<PackageVersion Include="Microsoft.Identity.Client" Version="4.81.0" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.81.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.15.0" />
<PackageVersion Include="Microsoft.Kiota.Authentication.Azure" Version="1.21.1" />
<PackageVersion Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.21.1" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Json" Version="1.21.1" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.16.0" />
<PackageVersion Include="Microsoft.Kiota.Abstractions" Version="1.22.2" />
<PackageVersion Include="Microsoft.Kiota.Authentication.Azure" Version="1.22.2" />
<PackageVersion Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.22.2" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Json" Version="1.22.2" />
<PackageVersion Include="Microsoft.ML.OnnxRuntime" Version="1.23.2" />
<PackageVersion Include="Microsoft.ML.OnnxRuntime.Gpu" Version="1.23.2" />
<PackageVersion Include="Microsoft.ML.Tokenizers.Data.Cl100kBase" Version="2.0.0" />
@@ -85,34 +88,34 @@
<PackageVersion Include="Microsoft.SemanticKernel.Core" Version="1.71.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Planners.OpenAI" Version="1.47.0-preview" />
<PackageVersion Include="Microsoft.VisualStudio.Threading" Version="17.14.15" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.2" />
<PackageVersion Include="ModelContextProtocol" Version="0.4.0-preview.3" />
<PackageVersion Include="MSTest.TestFramework" Version="3.8.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="Npgsql" Version="10.0.2" />
<PackageVersion Include="Npgsql" Version="10.0.3" />
<PackageVersion Include="OData2Linq" Version="2.2.0" />
<PackageVersion Include="OllamaSharp" Version="5.4.12" />
<PackageVersion Include="OpenAI" Version="2.9.1" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.14.0" />
<PackageVersion Include="OllamaSharp" Version="5.4.25" />
<PackageVersion Include="OpenAI" Version="2.10.0" />
<PackageVersion Include="OpenTelemetry" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Api" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Api.ProviderBuilderExtensions" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageVersion Include="PdfPig" Version="0.1.13" />
<PackageVersion Include="Pinecone.Client" Version="3.1.0" />
<PackageVersion Include="Prompty.Core" Version="0.2.3-beta" />
<PackageVersion Include="Scriban" Version="7.0.3" />
<PackageVersion Include="Prompty.Core" Version="2.0.0-beta.3" />
<PackageVersion Include="PuppeteerSharp" Version="20.2.5" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="10.0.2" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
<PackageVersion Include="System.IO.Packaging" Version="10.0.2" />
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.4" />
<PackageVersion Include="System.Memory.Data" Version="10.0.2" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Numerics.Tensors" Version="10.0.4" />
<PackageVersion Include="System.Text.Json" Version="10.0.4" />
<PackageVersion Include="System.ValueTuple" Version="4.6.1" />
<PackageVersion Include="System.Numerics.Tensors" Version="10.0.10" />
<PackageVersion Include="System.Text.Json" Version="10.0.6" />
<PackageVersion Include="System.ValueTuple" Version="4.6.2" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
<PackageVersion Include="A2A" Version="0.3.1-preview" />
<PackageVersion Include="A2A.AspNetCore" Version="0.3.1-preview" />
@@ -120,10 +123,10 @@
<!-- Tokenizers -->
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
<!-- Microsoft.Extensions.* -->
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="10.5.2" />
<PackageVersion Include="Microsoft.Extensions.AI.AzureAIInference" Version="10.0.0-preview.1.25559.3" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.4.0" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.2" />
@@ -132,27 +135,29 @@
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.6" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.Testing" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.2.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.2.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.4" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.9" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.2" />
<PackageVersion Include="Microsoft.Bcl.TimeProvider" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="10.2.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.2" />
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="10.5.2" />
<!-- Test -->
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="Moq" Version="[4.18.4]" />
<PackageVersion Include="FluentAssertions" Version="8.2.0" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.4" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.6" />
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="10.0.2" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.abstractions" Version="2.0.3" />
@@ -164,13 +169,12 @@
<PackageVersion Include="Humanizer" Version="2.14.1" />
<!-- Plugins -->
<PackageVersion Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
<PackageVersion Include="DuckDB.NET.Data.Full" Version="1.2.0" />
<PackageVersion Include="DuckDB.NET.Data" Version="1.1.3" />
<PackageVersion Include="MongoDB.Driver" Version="3.5.2" />
<PackageVersion Include="Microsoft.Graph" Version="5.94.0" />
<PackageVersion Include="Microsoft.OpenApi" Version="1.6.24" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.6.24" />
<PackageVersion Include="Microsoft.Graph" Version="5.105.0" />
<PackageVersion Include="Microsoft.Graph.Core" Version="3.2.6" />
<PackageVersion Include="Microsoft.OpenApi" Version="1.6.31" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.6.31" />
<PackageVersion Include="Microsoft.OpenApi.ApiManifest" Version="0.5.6-preview" />
<PackageVersion Include="Microsoft.Plugins.Manifest" Version="1.0.0-rc3" />
<PackageVersion Include="protobuf-net" Version="3.2.56" />
@@ -178,20 +182,18 @@
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="Fluid.Core" Version="2.31.0" />
<!-- Memory stores -->
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.54.0" />
<PackageVersion Include="Pgvector" Version="0.3.2" />
<PackageVersion Include="sqlite-vec" Version="0.1.7-alpha.2.1" />
<PackageVersion Include="NRedisStack" Version="1.0.0" />
<PackageVersion Include="Milvus.Client" Version="2.3.0-preview.1" />
<PackageVersion Include="Testcontainers" Version="4.10.0" />
<PackageVersion Include="Testcontainers.Milvus" Version="4.8.1" />
<PackageVersion Include="Testcontainers.MongoDB" Version="4.6.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.6.0" />
<PackageVersion Include="Testcontainers.PostgreSql" Version="4.6.0" />
<PackageVersion Include="Testcontainers.Qdrant" Version="4.10.0" />
<PackageVersion Include="Testcontainers.Redis" Version="4.6.0" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.1.2" />
<PackageVersion Include="Qdrant.Client" Version="1.15.1" />
<PackageVersion Include="Testcontainers.Milvus" Version="4.14.0" />
<PackageVersion Include="Testcontainers.MongoDB" Version="4.14.0" />
<!-- VectorData Dependencies -->
<PackageVersion Include="CommunityToolkit.VectorData.AzureAISearch" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.AzureDocumentDB" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.AzureCosmosDB" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.InMemory" Version="1.0.1" />
<PackageVersion Include="CommunityToolkit.VectorData.PgVector" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.Qdrant" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.Redis" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.Weaviate" Version="1.0.0" />
<!-- Symbols -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<!-- Toolset -->
@@ -242,4 +244,4 @@
<PackageVersion Include="NAudio" Version="2.2.1" />
<PackageVersion Include="WebRtcVadSharp" Version="1.3.2" />
</ItemGroup>
</Project>
</Project>
-50
View File
@@ -1,50 +0,0 @@
{
"solution": {
"path": "SK-dotnet.slnx",
"projects":
[
"src/VectorData/AzureAISearch/AzureAISearch.csproj",
"src/VectorData/CosmosMongoDB/CosmosMongoDB.csproj",
"src/VectorData/CosmosNoSql/CosmosNoSql.csproj",
"src/VectorData/Chroma/Chroma.csproj",
"src/VectorData/InMemory/InMemory.csproj",
"src/VectorData/Milvus/Milvus.csproj",
"src/VectorData/MongoDB/MongoDB.csproj",
"src/VectorData/Pinecone/Pinecone.csproj",
"src/VectorData/PgVector/PgVector.csproj",
"src/VectorData/Qdrant/Qdrant.csproj",
"src/VectorData/Redis/Redis.csproj",
"src/VectorData/SqliteVec/SqliteVec.csproj",
"src/VectorData/SqlServer/SqlServer.csproj",
"src/VectorData/Weaviate/Weaviate.csproj",
"src/VectorData/VectorData.Abstractions/VectorData.Abstractions.csproj",
"test/VectorData/AzureAISearch.UnitTests/AzureAISearch.UnitTests.csproj",
"test/VectorData/AzureAISearch.ConformanceTests/AzureAISearch.ConformanceTests.csproj",
"test/VectorData/CosmosMongoDB.UnitTests/CosmosMongoDB.UnitTests.csproj",
"test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoDB.ConformanceTests.csproj",
"test/VectorData/CosmosNoSql.UnitTests/CosmosNoSql.UnitTests.csproj",
"test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSql.ConformanceTests.csproj",
"test/VectorData/InMemory.UnitTests/InMemory.UnitTests.csproj",
"test/VectorData/InMemory.ConformanceTests/InMemory.ConformanceTests.csproj",
"test/VectorData/MongoDB.UnitTests/MongoDB.UnitTests.csproj",
"test/VectorData/MongoDB.ConformanceTests/MongoDB.ConformanceTests.csproj",
"test/VectorData/Pinecone.UnitTests/Pinecone.UnitTests.csproj",
"test/VectorData/Pinecone.ConformanceTests/Pinecone.ConformanceTests.csproj",
"test/VectorData/PgVector.UnitTests/PgVector.UnitTests.csproj",
"test/VectorData/PgVector.ConformanceTests/PgVector.ConformanceTests.csproj",
"test/VectorData/Qdrant.UnitTests/Qdrant.UnitTests.csproj",
"test/VectorData/Qdrant.ConformanceTests/Qdrant.ConformanceTests.csproj",
"test/VectorData/Redis.UnitTests/Redis.UnitTests.csproj",
"test/VectorData/Redis.ConformanceTests/Redis.ConformanceTests.csproj",
"test/VectorData/SqliteVec.UnitTests/SqliteVec.UnitTests.csproj",
"test/VectorData/SqliteVec.ConformanceTests/SqliteVec.ConformanceTests.csproj",
"test/VectorData/SqlServer.ConformanceTests/SqlServer.ConformanceTests.csproj",
"test/VectorData/Weaviate.UnitTests/Weaviate.UnitTests.csproj",
"test/VectorData/Weaviate.ConformanceTests/Weaviate.ConformanceTests.csproj",
"test/VectorData/VectorData.ConformanceTests/VectorData.ConformanceTests.csproj"
]
}
}
+30
View File
@@ -0,0 +1,30 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path="../.editorconfig" />
<File Path="../.github/workflows/dotnet-format.yml" />
<File Path="../.gitignore" />
<File Path="../nuget.config" />
<File Path="../README.md" />
<File Path="Directory.Build.props" />
<File Path="Directory.Build.targets" />
<File Path="Directory.Packages.props" />
<File Path="docs/EXPERIMENTS.md" />
<File Path="global.json" />
</Folder>
<Folder Name="/Solution Items/nuget/">
<File Path="nuget/icon.png" />
<File Path="nuget/nuget-package.props" />
<File Path="nuget/NUGET.md" />
<File Path="nuget/VECTORDATA-CONNECTORS-NUGET.md" />
</Folder>
<Folder Name="/src/" />
<Folder Name="/src/VectorData/">
<File Path="src/VectorData/Directory.Build.props" />
<Project Path="src/VectorData/Chroma/Chroma.csproj" />
<Project Path="src/VectorData/Milvus/Milvus.csproj" />
</Folder>
<Folder Name="/test/" />
<Folder Name="/test/VectorData/">
<Project Path="test/VectorData/Chroma.UnitTests/Chroma.UnitTests.csproj" />
</Folder>
</Solution>
+5
View File
@@ -1,5 +1,10 @@
# Get Started with Semantic Kernel ⚡
> [!IMPORTANT]
> Semantic Kernel is now [Microsoft Agent Framework](https://github.com/microsoft/agent-framework)! Microsoft Agent Framework (MAF) is the enterprise‑ready successor to Semantic Kernel. Microsoft Agent Framework is now available at version 1.0 as a production-ready release: stable APIs, and a commitment to long-term support. Whether you're building a single assistant or orchestrating a fleet of specialized agents, Microsoft Agent Framework 1.0 gives you enterprise-grade multi-agent orchestration, multi-provider model support, and cross-runtime interoperability via A2A and MCP.
>
> Learn more about Semantic Kernel and Agent Framework here: [Semantic Kernel and Microsoft Agent Framework on the Agent Framework blog](https://devblogs.microsoft.com/agent-framework/semantic-kernel-and-microsoft-agent-framework/), and try out the [Semantic Kernel migration guide](https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel).
## OpenAI / Azure OpenAI API keys
To run the LLM prompts and semantic functions in the examples below, make sure
-47
View File
@@ -121,24 +121,6 @@
<Project Path="src/Connectors/Connectors.OpenAI.UnitTests/Connectors.OpenAI.UnitTests.csproj" />
<Project Path="src/Connectors/Connectors.OpenAI/Connectors.OpenAI.csproj" />
</Folder>
<Folder Name="/src/VectorData/">
<File Path="src/VectorData/Directory.Build.props" />
<Project Path="src/VectorData/AzureAISearch/AzureAISearch.csproj" />
<Project Path="src/VectorData/Chroma/Chroma.csproj" />
<Project Path="src/VectorData/CosmosMongoDB/CosmosMongoDB.csproj" />
<Project Path="src/VectorData/CosmosNoSql/CosmosNoSql.csproj" />
<Project Path="src/VectorData/InMemory/InMemory.csproj" />
<Project Path="src/VectorData/Milvus/Milvus.csproj" />
<Project Path="src/VectorData/MongoDB/MongoDB.csproj" />
<Project Path="src/VectorData/PgVector/PgVector.csproj" />
<Project Path="src/VectorData/Pinecone/Pinecone.csproj" />
<Project Path="src/VectorData/Qdrant/Qdrant.csproj" />
<Project Path="src/VectorData/Redis/Redis.csproj" />
<Project Path="src/VectorData/SqliteVec/SqliteVec.csproj" />
<Project Path="src/VectorData/SqlServer/SqlServer.csproj" />
<Project Path="src/VectorData/VectorData.Abstractions/VectorData.Abstractions.csproj" />
<Project Path="src/VectorData/Weaviate/Weaviate.csproj" />
</Folder>
<Folder Name="/src/experimental/">
<Project Path="src/Experimental/Orchestration.Flow.IntegrationTests/Experimental.Orchestration.Flow.IntegrationTests.csproj" />
<Project Path="src/Experimental/Orchestration.Flow.UnitTests/Experimental.Orchestration.Flow.UnitTests.csproj" />
@@ -292,33 +274,4 @@
<Project Path="src/Plugins/Plugins.UnitTests/Plugins.UnitTests.csproj" />
<Project Path="src/Plugins/Plugins.Web/Plugins.Web.csproj" />
</Folder>
<Folder Name="/test/" />
<Folder Name="/test/VectorData/">
<Project Path="test/VectorData/AzureAISearch.ConformanceTests/AzureAISearch.ConformanceTests.csproj" />
<Project Path="test/VectorData/AzureAISearch.UnitTests/AzureAISearch.UnitTests.csproj" />
<Project Path="test/VectorData/Chroma.UnitTests/Chroma.UnitTests.csproj" />
<Project Path="test/VectorData/CosmosMongoDB.ConformanceTests/CosmosMongoDB.ConformanceTests.csproj" />
<Project Path="test/VectorData/CosmosMongoDB.UnitTests/CosmosMongoDB.UnitTests.csproj" />
<Project Path="test/VectorData/CosmosNoSql.ConformanceTests/CosmosNoSql.ConformanceTests.csproj" />
<Project Path="test/VectorData/CosmosNoSql.UnitTests/CosmosNoSql.UnitTests.csproj" />
<Project Path="test/VectorData/InMemory.ConformanceTests/InMemory.ConformanceTests.csproj" />
<Project Path="test/VectorData/InMemory.UnitTests/InMemory.UnitTests.csproj" />
<Project Path="test/VectorData/MongoDB.ConformanceTests/MongoDB.ConformanceTests.csproj" />
<Project Path="test/VectorData/MongoDB.UnitTests/MongoDB.UnitTests.csproj" />
<Project Path="test/VectorData/PgVector.ConformanceTests/PgVector.ConformanceTests.csproj" />
<Project Path="test/VectorData/PgVector.UnitTests/PgVector.UnitTests.csproj" />
<Project Path="test/VectorData/Pinecone.ConformanceTests/Pinecone.ConformanceTests.csproj" />
<Project Path="test/VectorData/Pinecone.UnitTests/Pinecone.UnitTests.csproj" />
<Project Path="test/VectorData/Qdrant.ConformanceTests/Qdrant.ConformanceTests.csproj" />
<Project Path="test/VectorData/Qdrant.UnitTests/Qdrant.UnitTests.csproj" />
<Project Path="test/VectorData/Redis.ConformanceTests/Redis.ConformanceTests.csproj" />
<Project Path="test/VectorData/Redis.UnitTests/Redis.UnitTests.csproj" />
<Project Path="test/VectorData/SqliteVec.ConformanceTests/SqliteVec.ConformanceTests.csproj" />
<Project Path="test/VectorData/SqliteVec.UnitTests/SqliteVec.UnitTests.csproj" />
<Project Path="test/VectorData/SqlServer.ConformanceTests/SqlServer.ConformanceTests.csproj" />
<Project Path="test/VectorData/VectorData.ConformanceTests/VectorData.ConformanceTests.csproj" />
<Project Path="test/VectorData/VectorData.UnitTests/VectorData.UnitTests.csproj" />
<Project Path="test/VectorData/Weaviate.ConformanceTests/Weaviate.ConformanceTests.csproj" />
<Project Path="test/VectorData/Weaviate.UnitTests/Weaviate.UnitTests.csproj" />
</Folder>
</Solution>
-16
View File
@@ -32,22 +32,6 @@
"src\\Connectors\\Connectors.Onnx\\Connectors.Onnx.csproj",
"src\\Connectors\\Connectors.OpenAI\\Connectors.OpenAI.csproj",
"src\\VectorData\\AzureAISearch\\AzureAISearch.csproj",
"src\\VectorData\\Chroma\\Chroma.csproj",
"src\\VectorData\\CosmosMongoDB\\CosmosMongoDB.csproj",
"src\\VectorData\\CosmosNoSql\\CosmosNoSql.csproj",
"src\\VectorData\\InMemory\\InMemory.csproj",
"src\\VectorData\\Milvus\\Milvus.csproj",
"src\\VectorData\\MongoDB\\MongoDB.csproj",
"src\\VectorData\\PgVector\\PgVector.csproj",
"src\\VectorData\\Pinecone\\Pinecone.csproj",
"src\\VectorData\\Qdrant\\Qdrant.csproj",
"src\\VectorData\\Redis\\Redis.csproj",
"src\\VectorData\\SqliteVec\\SqliteVec.csproj",
"src\\VectorData\\SqlServer\\SqlServer.csproj",
"src\\VectorData\\VectorData.Abstractions\\VectorData.Abstractions.csproj",
"src\\VectorData\\Weaviate\\Weaviate.csproj",
"src\\Experimental\\Orchestration.Flow\\Experimental.Orchestration.Flow.csproj",
"src\\Experimental\\Process.Abstractions\\Process.Abstractions.csproj",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.100",
"version": "10.0.303",
"rollForward": "major",
"allowPrerelease": false
}
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
+2 -2
View File
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<!-- Central version prefix - applies to all nuget packages. -->
<VersionPrefix>1.74.0</VersionPrefix>
<VersionPrefix>1.80.1</VersionPrefix>
<PackageVersion Condition="'$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix)</PackageVersion>
<PackageVersion Condition="'$(VersionSuffix)' == ''">$(VersionPrefix)</PackageVersion>
@@ -9,7 +9,7 @@
<IsPackable>true</IsPackable>
<!-- Package validation. Baseline Version should be the latest version available on NuGet. -->
<PackageValidationBaselineVersion>1.73.0</PackageValidationBaselineVersion>
<PackageValidationBaselineVersion>1.80.0</PackageValidationBaselineVersion>
<!-- Validate assembly attributes only for Publish builds -->
<NoWarn Condition="'$(Configuration)' != 'Publish'">$(NoWarn);CP0003</NoWarn>
<!-- Do not validate reference assemblies -->
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Agents.AI.Workflows" />
</ItemGroup>
@@ -79,13 +79,13 @@ async Task AFConcurrentAgentWorkflow()
var spanishAgent = GetAFTranslationAgent("Spanish", client);
var concurrentAgentWorkflow = AgentWorkflowBuilder.BuildConcurrent([frenchAgent, spanishAgent]);
await using StreamingRun run = await InProcessExecution.StreamAsync(concurrentAgentWorkflow, "Hello, world!");
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(concurrentAgentWorkflow, "Hello, world!");
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
string? lastExecutorId = null;
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is AgentRunUpdateEvent e)
if (evt is AgentResponseUpdateEvent e)
{
if (string.IsNullOrEmpty(e.Update.Text))
{
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Agents.AI.Workflows" />
</ItemGroup>
@@ -82,13 +82,13 @@ async Task AFSequentialAgentWorkflow()
var sequentialAgentWorkflow = AgentWorkflowBuilder.BuildSequential(
[frenchAgent, spanishAgent, englishAgent]);
await using StreamingRun run = await InProcessExecution.StreamAsync(sequentialAgentWorkflow, "Hello, world!");
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(sequentialAgentWorkflow, "Hello, world!");
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
string? lastExecutorId = null;
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is AgentRunUpdateEvent e)
if (evt is AgentResponseUpdateEvent e)
{
if (string.IsNullOrEmpty(e.Update.Text))
{
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Agents.AI.Workflows" />
</ItemGroup>
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
#pragma warning disable MAAIW001 // Experimental: HandoffWorkflowBuilder
using System.ComponentModel;
using System.Text.Json;
using Azure.AI.OpenAI;
@@ -207,13 +209,13 @@ async Task AFHandoffAgentWorkflow()
Console.WriteLine($"User: {query}");
messages.Add(new(ChatRole.User, query));
await using var run = await InProcessExecution.StreamAsync(handoffAgentWorkflow, messages);
await using var run = await InProcessExecution.RunStreamingAsync(handoffAgentWorkflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
string? lastExecutorId = null;
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is AgentRunUpdateEvent e)
if (evt is AgentResponseUpdateEvent e)
{
if (string.IsNullOrEmpty(e.Update.Text) && e.Update.Contents.Count == 0)
{
@@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.SemanticKernel;
@@ -67,7 +68,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -80,9 +81,9 @@ async Task SKAgent_As_AFAgentAsync()
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
if (thread is ChatClientAgentSession chatSession)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
await azureAgentClient.Threads.DeleteThreadAsync(chatSession.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -91,29 +92,23 @@ async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
// AF 1.0: Use AIProjectClient.AsAIAgent() from Microsoft.Agents.AI.Foundry
var projectClient = new AIProjectClient(new Uri(azureEndpoint), new AzureCliCredential());
var agent = await azureAgentClient.CreateAIAgentAsync(
var agent = projectClient.AsAIAgent(
deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
instructions: "You are good at telling jokes.",
name: "GenerateStory");
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
@@ -2,6 +2,7 @@
using System.ComponentModel;
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
@@ -85,7 +86,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { Tools = [AIFunctionFactory.Create(GetWeather)] });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -98,9 +99,9 @@ async Task SKAgent_As_AFAgentAsync()
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
if (thread is ChatClientAgentSession chatSession)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
await azureAgentClient.Threads.DeleteThreadAsync(chatSession.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -109,26 +110,22 @@ async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
var agent = new AIProjectClient(new Uri(azureEndpoint), new AzureCliCredential())
.AsAIAgent(model: deploymentName,
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
var agent = await azureAgentClient.CreateAIAgentAsync(deploymentName, instructions: "Answer questions about the menu");
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { Tools = [AIFunctionFactory.Create(GetWeather)] });
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
// No cleanup needed - non-hosted path doesn't create server-side resources.
}
@@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
@@ -90,7 +91,7 @@ async Task SKAgent_As_AFAgentAsync()
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
@@ -103,9 +104,9 @@ async Task SKAgent_As_AFAgentAsync()
// Clean up
var azureAgentClient = serviceProvider.GetRequiredService<PersistentAgentsClient>();
if (thread is ChatClientAgentThread chatThread)
if (thread is ChatClientAgentSession chatSession)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
await azureAgentClient.Threads.DeleteThreadAsync(chatSession.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -115,36 +116,29 @@ async Task AFAgentAsync()
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new PersistentAgentsClient(azureEndpoint, new AzureCliCredential()));
serviceCollection.AddSingleton((sp) => new AIProjectClient(new Uri(azureEndpoint), new AzureCliCredential()));
serviceCollection.AddTransient<AIAgent>((sp) =>
{
var azureAgentClient = sp.GetRequiredService<PersistentAgentsClient>();
return azureAgentClient.CreateAIAgent(
deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
var client = sp.GetRequiredService<AIProjectClient>();
return client.AsAIAgent(
deploymentName,
instructions: "You are good at telling jokes.",
name: "GenerateStory");
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, thread);
var result = await agent.RunAsync(userInput, session);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread))
await foreach (var update in agent.RunStreamingAsync(userInput, session))
{
Console.Write(update);
}
// Clean up
var azureAgentClient = serviceProvider.GetRequiredService<PersistentAgentsClient>();
if (thread is ChatClientAgentThread chatThread)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
// No cleanup needed - non-hosted path doesn't create server-side resources.
}
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.AzureAI" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
@@ -2,6 +2,7 @@
using System.Text;
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
@@ -76,7 +77,7 @@ async Task SKAgent_As_AFAgentAsync()
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
@@ -124,9 +125,9 @@ async Task SKAgent_As_AFAgentAsync()
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
if (thread is ChatClientAgentSession chatSession)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
await azureAgentClient.Threads.DeleteThreadAsync(chatSession.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -135,59 +136,15 @@ async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
var agent = await azureAgentClient.CreateAIAgentAsync(deploymentName, tools: [new CodeInterpreterToolDefinition()]);
var thread = agent.GetNewThread();
// Note: Code interpreter via hosted APIs requires versioned Foundry Agents.
// This sample creates a basic agent without code interpreter capabilities.
var agent = new AIProjectClient(new Uri(azureEndpoint), new AzureCliCredential())
.AsAIAgent(deploymentName, instructions: "You are a helpful assistant with code execution capabilities.");
var result = await agent.RunAsync(userInput, thread);
var session = await agent.CreateSessionAsync();
var result = await agent.RunAsync(userInput, session);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
// To capture the code interpreter input we need to break glass all the updates raw representations, to check for the RunStepDetailsUpdate type and
// get the CodeInterpreterInput property which contains the generated code.
// Note: Similar logic would needed for each individual update if used in the agent.RunStreamingAsync streaming API to aggregate or yield the generated code.
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Update the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await azureAgentClient.Threads.DeleteThreadAsync(chatThread.ConversationId);
}
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
// No cleanup needed - non-hosted path doesn't create server-side resources.
}
@@ -6,7 +6,7 @@ using Microsoft.Agents.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Chat;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
@@ -65,7 +65,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -83,9 +83,9 @@ async Task AFAgent()
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetChatClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
.AsAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -6,7 +6,7 @@ using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
using OpenAI.Chat;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
@@ -73,7 +73,7 @@ async Task SKAgent_As_AFAgentAsync()
async Task AFAgent()
{
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetChatClient(deploymentName)
.CreateAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
.AsAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
Console.WriteLine("\n=== AF Agent Response ===\n");
@@ -7,7 +7,7 @@ using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
using OpenAI.Chat;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
@@ -72,7 +72,7 @@ async Task AFAgent()
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<AIAgent>((sp) => new AzureOpenAIClient(new(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
.AsAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
@@ -9,7 +9,7 @@ using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using OpenAI;
using OpenAI.Chat;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
@@ -59,7 +59,7 @@ async Task AFAgent()
new Uri(endpoint),
new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(instructions: "You are a helpful assistant", tools: tools);
.AsAIAgent(instructions: "You are a helpful assistant", tools: tools);
// Run the agent with the OpenAPI function tools.
Console.WriteLine(await agent.RunAsync("Please list the names, colors and descriptions of all the labels available in the microsoft/agent-framework repository on github."));
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,120 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await SKAgent_As_AFAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var _ = Kernel.CreateBuilder().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
var assistantsClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName, name: "Joker", instructions: "You are good at telling jokes.");
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgent()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var _ = Kernel.CreateBuilder().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
var assistantsClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName, name: "Joker", instructions: "You are good at telling jokes.");
// Create the agent
OpenAIAssistantAgent skAgent = new(assistant, assistantsClient);
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
var agent = await assistantClient.CreateAIAgentAsync(deploymentName, name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,147 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "What is the weather like in Amsterdam?";
[KernelFunction]
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await SKAgent_As_AFAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var builder = Kernel.CreateBuilder();
var assistantsClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName,
instructions: "You are a helpful assistant");
OpenAIAssistantAgent agent = new(assistant, assistantsClient)
{
Kernel = builder.Build(),
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
}),
};
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
await foreach (var result in agent.InvokeAsync(userInput, thread))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgent()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var builder = Kernel.CreateBuilder();
var assistantsClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName,
instructions: "You are a helpful assistant");
OpenAIAssistantAgent skAgent = new(assistant, assistantsClient)
{
Kernel = builder.Build(),
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
}),
};
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
skAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
var agent = await assistantClient.CreateAIAgentAsync(deploymentName,
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,144 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await SKAgent_As_AFAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient());
serviceCollection.AddKernel().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
serviceCollection.AddTransient((sp) =>
{
var assistantsClient = sp.GetRequiredService<AssistantClient>();
Assistant assistant = assistantsClient.CreateAssistant(deploymentName, new() { Name = "Joker", Instructions = "You are good at telling jokes." });
return new OpenAIAssistantAgent(assistant, assistantsClient);
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<OpenAIAssistantAgent>();
// Create a thread for the agent conversation.
var assistantsClient = serviceProvider.GetRequiredService<AssistantClient>();
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgent()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient());
serviceCollection.AddKernel().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
serviceCollection.AddTransient((sp) =>
{
var assistantsClient = sp.GetRequiredService<AssistantClient>();
Assistant assistant = assistantsClient.CreateAssistant(deploymentName, new() { Name = "Joker", Instructions = "You are good at telling jokes." });
return new OpenAIAssistantAgent(assistant, assistantsClient);
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var skAgent = serviceProvider.GetRequiredService<OpenAIAssistantAgent>();
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
var assistantClient = serviceProvider.GetRequiredService<AssistantClient>();
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient());
serviceCollection.AddTransient<AIAgent>((sp) =>
{
var assistantClient = sp.GetRequiredService<AssistantClient>();
return assistantClient.CreateAIAgent(deploymentName, name: "Joker", instructions: "You are good at telling jokes.");
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
var assistantClient = serviceProvider.GetRequiredService<AssistantClient>();
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,196 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Create a python code file using the code interpreter tool with a code ready to determine the values in the Fibonacci sequence that are less then the value of 101";
var assistantsClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetAssistantClient();
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await SKAgent_As_AFAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var _ = Kernel.CreateBuilder().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName, enableCodeInterpreter: true);
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
// Respond to user input
await foreach (var content in agent.InvokeAsync(userInput, thread))
{
if (!string.IsNullOrWhiteSpace(content.Message.Content))
{
bool isCode = content.Message.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false;
Console.WriteLine($"\n# {content.Message.Role}{(isCode ? "\n# Generated Code:\n" : ":")}{content.Message.Content}");
}
// Check for the citations
foreach (var item in content.Message.Items)
{
// Process each item in the message
if (item is AnnotationContent annotation)
{
if (annotation.Kind != AnnotationKind.UrlCitation)
{
Console.WriteLine($" [{item.GetType().Name}] {annotation.Label}: File #{annotation.ReferenceId}");
}
}
else if (item is FileReferenceContent fileReference)
{
Console.WriteLine($" [{item.GetType().Name}] File #{fileReference.FileId}");
}
}
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgent()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var _ = Kernel.CreateBuilder().AddAzureOpenAIChatClient(deploymentName, endpoint, new AzureCliCredential());
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(deploymentName, enableCodeInterpreter: true);
// Create the agent
OpenAIAssistantAgent skAgent = new(assistant, assistantsClient);
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Check for the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = await assistantsClient.CreateAIAgentAsync(deploymentName, tools: [new HostedCodeInterpreterTool()]);
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Check for the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
@@ -5,7 +5,7 @@ using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -66,7 +66,7 @@ async Task SKAgent_As_AFAgentAsync()
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -84,17 +84,17 @@ async Task AFAgentAsync()
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetResponsesClient().AsIChatClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
.GetResponsesClient()
.AsAIAgent(model: deploymentName, name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
Console.Write(update);
}
@@ -7,7 +7,7 @@ using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -134,7 +134,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
@@ -180,10 +180,10 @@ async Task AFAgentAsync()
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetResponsesClient().AsIChatClient(deploymentName)
.CreateAIAgent(name: "Thinker", instructions: "You are good at thinking hard before answering.");
.GetResponsesClient()
.AsAIAgent(model: deploymentName, name: "Thinker", instructions: "You are good at thinking hard before answering.");
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
@@ -194,7 +194,7 @@ async Task AFAgentAsync()
}
});
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
// Retrieve the thinking as a full text block requires flattening multiple TextReasoningContents from multiple messages content lists.
string assistantThinking = string.Join("\n", result.Messages
@@ -207,7 +207,7 @@ async Task AFAgentAsync()
Console.WriteLine($"Assistant: \n{assistantText}\n---\n");
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
var thinkingContents = update.Contents
.OfType<TextReasoningContent>()
@@ -6,7 +6,7 @@ using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -66,8 +66,8 @@ async Task SKAgent_As_AFAgentAsync()
async Task AFAgentAsync()
{
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetResponsesClient().AsIChatClient(deploymentName)
.CreateAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
.GetResponsesClient()
.AsAIAgent(model: deploymentName, instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
Console.WriteLine("\n=== AF Agent Response ===\n");
@@ -6,7 +6,7 @@ using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -71,8 +71,8 @@ async Task AFAgentAsync()
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<AIAgent>((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetResponsesClient().AsIChatClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
.GetResponsesClient()
.AsAIAgent(model: deploymentName, name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
@@ -5,6 +5,7 @@ using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Chat;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
@@ -64,7 +65,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -83,9 +84,9 @@ async Task AFAgentAsync()
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetChatClient(model)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
.AsAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -6,6 +6,7 @@ using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
using OpenAI.Chat;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
@@ -65,7 +66,7 @@ async Task SKAgent_As_AFAgentAsync()
var agent = skAgent.AsAIAgent();
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -86,7 +87,7 @@ async Task SKAgent_As_AFAgentAsync()
async Task AFAgentAsync()
{
var agent = new OpenAIClient(apiKey).GetChatClient(model).CreateAIAgent(
var agent = new OpenAIClient(apiKey).GetChatClient(model).AsAIAgent(
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
@@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
using OpenAI.Chat;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
@@ -70,7 +71,7 @@ async Task AFAgentAsync()
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<AIAgent>((sp) => new OpenAIClient(apiKey)
.GetChatClient(model)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
.AsAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,116 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgentAsync();
await SKAgent_As_AFAgentAsync();
await AFAgentAsync();
async Task SKAgentAsync()
{
Console.WriteLine("\n=== SK Agent ===\n");
var assistantsClient = new AssistantClient(apiKey);
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(model, name: "Joker", instructions: "You are good at telling jokes.");
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
// Example of Semantic Kernel Agent code converted as an Agent Framework Agent
async Task SKAgent_As_AFAgentAsync()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var assistantsClient = new AssistantClient(apiKey);
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(model, name: "Joker", instructions: "You are good at telling jokes.");
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
var afAgent = agent.AsAIAgent();
var thread = afAgent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await afAgent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in afAgent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AssistantClient(apiKey);
var agent = await assistantClient.CreateAIAgentAsync(model, name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,145 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
var userInput = "What is the weather like in Amsterdam?";
[KernelFunction]
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
Console.WriteLine($"User Input: {userInput}");
await SKAgentAsync();
await SKAgent_As_AFAgentAsync();
await AFAgentAsync();
async Task SKAgentAsync()
{
Console.WriteLine("\n=== SK Agent ===\n");
var builder = Kernel.CreateBuilder();
var assistantsClient = new AssistantClient(apiKey);
Assistant assistant = await assistantsClient.CreateAssistantAsync(model,
instructions: "You are a helpful assistant");
OpenAIAssistantAgent agent = new(assistant, assistantsClient)
{
Kernel = builder.Build(),
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
}),
};
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
await foreach (var result in agent.InvokeAsync(userInput, thread))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgentAsync()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var builder = Kernel.CreateBuilder();
var assistantsClient = new AssistantClient(apiKey);
Assistant assistant = await assistantsClient.CreateAssistantAsync(model,
instructions: "You are a helpful assistant");
OpenAIAssistantAgent skAgent = new(assistant, assistantsClient)
{
Kernel = builder.Build(),
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
}),
};
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
skAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AssistantClient(apiKey);
var agent = await assistantClient.CreateAIAgentAsync(model,
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,142 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgentAsync();
await SKAgent_As_AFAgentAsync();
await AFAgentAsync();
async Task SKAgentAsync()
{
Console.WriteLine("\n=== SK Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AssistantClient(apiKey));
serviceCollection.AddKernel().AddOpenAIChatClient(model, apiKey);
serviceCollection.AddTransient((sp) =>
{
var assistantsClient = sp.GetRequiredService<AssistantClient>();
Assistant assistant = assistantsClient.CreateAssistant(model, new() { Name = "Joker", Instructions = "You are good at telling jokes." });
return new OpenAIAssistantAgent(assistant, assistantsClient);
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<OpenAIAssistantAgent>();
// Create a thread for the agent conversation.
var assistantsClient = serviceProvider.GetRequiredService<AssistantClient>();
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgentAsync()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AssistantClient(apiKey));
serviceCollection.AddKernel().AddOpenAIChatClient(model, apiKey);
serviceCollection.AddTransient((sp) =>
{
var assistantsClient = sp.GetRequiredService<AssistantClient>();
Assistant assistant = assistantsClient.CreateAssistant(model, new() { Name = "Joker", Instructions = "You are good at telling jokes." });
return new OpenAIAssistantAgent(assistant, assistantsClient);
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var skAgent = serviceProvider.GetRequiredService<OpenAIAssistantAgent>();
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
var assistantClient = serviceProvider.GetRequiredService<AssistantClient>();
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AssistantClient(apiKey));
serviceCollection.AddTransient((sp) =>
{
var assistantClient = sp.GetRequiredService<AssistantClient>();
return assistantClient.CreateAIAgent(model, name: "Joker", instructions: "You are good at telling jokes.");
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
// Clean up
var assistantClient = serviceProvider.GetRequiredService<AssistantClient>();
if (thread is ChatClientAgentThread chatThread)
{
await assistantClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1707;CA2007;VSTHRD111</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.Abstractions" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Agents\Core\Agents.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Agents\OpenAI\Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\SemanticKernel.MetaPackage\SemanticKernel.MetaPackage.csproj" />
</ItemGroup>
</Project>
@@ -1,192 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var model = System.Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o";
var userInput = "Create a python code file using the code interpreter tool with a code ready to determine the values in the Fibonacci sequence that are less then the value of 101";
var assistantsClient = new AssistantClient(apiKey);
Console.WriteLine($"User Input: {userInput}");
await SKAgentAsync();
await SKAgent_As_AFAgentAsync();
await AFAgentAsync();
async Task SKAgentAsync()
{
Console.WriteLine("\n=== SK Agent ===\n");
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(model, enableCodeInterpreter: true);
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
// Respond to user input
await foreach (var content in agent.InvokeAsync(userInput, thread))
{
if (!string.IsNullOrWhiteSpace(content.Message.Content))
{
bool isCode = content.Message.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false;
Console.WriteLine($"\n# {content.Message.Role}{(isCode ? "\n# Generated Code:\n" : ":")}{content.Message.Content}");
}
// Check for the citations
foreach (var item in content.Message.Items)
{
// Process each item in the message
if (item is AnnotationContent annotation)
{
if (annotation.Kind != AnnotationKind.UrlCitation)
{
Console.WriteLine($" [{item.GetType().Name}] {annotation.Label}: File #{annotation.ReferenceId}");
}
}
else if (item is FileReferenceContent fileReference)
{
Console.WriteLine($" [{item.GetType().Name}] File #{fileReference.FileId}");
}
}
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task SKAgent_As_AFAgentAsync()
{
Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n");
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(model, enableCodeInterpreter: true);
// Create the agent
OpenAIAssistantAgent skAgent = new(assistant, assistantsClient);
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Check for the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = await assistantsClient.CreateAIAgentAsync(model, tools: [new HostedCodeInterpreterTool()]);
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Check for the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
if (thread is ChatClientAgentThread chatThread)
{
await assistantsClient.DeleteThreadAsync(chatThread.ConversationId);
}
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
@@ -4,6 +4,7 @@ using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -63,7 +64,7 @@ async Task SKAgent_As_AFAgentAsync()
var agent = skAgent.AsAIAgent();
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
@@ -80,17 +81,17 @@ async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var agent = new OpenAIClient(apiKey).GetResponsesClient()
.AsAIAgent(model: model, name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
Console.Write(update);
}
@@ -6,6 +6,7 @@ using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -131,7 +132,7 @@ async Task SKAgent_As_AFAgentAsync()
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var thread = agent.GetNewThread();
var thread = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
@@ -176,10 +177,10 @@ async Task AFAgentAsync()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model)
.CreateAIAgent(name: "Thinker", instructions: "You are at thinking hard before answering.");
var agent = new OpenAIClient(apiKey).GetResponsesClient()
.AsAIAgent(model: model, name: "Thinker", instructions: "You are at thinking hard before answering.");
var thread = agent.GetNewThread();
var session = await agent.CreateSessionAsync();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
@@ -190,7 +191,7 @@ async Task AFAgentAsync()
}
});
var result = await agent.RunAsync(userInput, thread, agentOptions);
var result = await agent.RunAsync(userInput, session, agentOptions);
// Retrieve the thinking as a full text block requires flattening multiple TextReasoningContents from multiple messages content lists.
string assistantThinking = string.Join("\n", result.Messages
@@ -203,7 +204,7 @@ async Task AFAgentAsync()
Console.WriteLine($"Assistant: \n{assistantText}\n---\n");
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
await foreach (var update in agent.RunStreamingAsync(userInput, session, agentOptions))
{
var thinkingContents = update.Contents
.OfType<TextReasoningContent>()
@@ -5,6 +5,7 @@ using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -63,7 +64,8 @@ async Task SKAgent_As_AFAgentAsync()
async Task AFAgentAsync()
{
var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model).CreateAIAgent(
var agent = new OpenAIClient(apiKey).GetResponsesClient().AsAIAgent(
model: model,
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
@@ -5,6 +5,7 @@ using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -65,8 +66,8 @@ async Task AFAgentAsync()
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient((sp) => new OpenAIClient(apiKey)
.GetResponsesClient().AsIChatClient(model)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
.GetResponsesClient()
.AsAIAgent(model: model, name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
@@ -2,10 +2,10 @@
using Azure.AI.OpenAI;
using Azure.Identity;
using CommunityToolkit.VectorData.InMemory;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.InMemory;
using Microsoft.SemanticKernel.Functions;
namespace Agents;
@@ -2,11 +2,11 @@
using Azure.AI.OpenAI;
using Azure.Identity;
using CommunityToolkit.VectorData.InMemory;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.InMemory;
using Microsoft.SemanticKernel.Data;
namespace Agents;
+1 -1
View File
@@ -19,7 +19,7 @@ Prefix|Description
---|---
OpenAIAssistant|How to use agents based on the [Open AI Assistant API](https://platform.openai.com/docs/assistants).
MixedChat|How to combine different agent types.
ComplexChat|How to deveop complex agent chat solutions.
ComplexChat|How to develop complex agent chat solutions.
Legacy|How to use the legacy _Experimental Agent API_.
## Legacy Agents
@@ -77,18 +77,18 @@ public class SemanticCachingWithFilters(ITestOutputHelper output) : BaseTest(out
}
/// <summary>
/// Executing similar requests two times using Azure Cosmos DB for MongoDB caching store to compare execution time and results.
/// Executing similar requests two times using Azure DocumentDB caching store to compare execution time and results.
/// Second execution is faster, because the result is returned from cache.
/// How to setup Azure Cosmos DB for MongoDB cluster: https://learn.microsoft.com/en-gb/azure/cosmos-db/mongodb/vcore/quickstart-portal
/// How to set up Azure DocumentDB: https://learn.microsoft.com/azure/documentdb/quickstart-portal
/// </summary>
[Fact]
public async Task CosmosMongoDBCacheAsync()
public async Task DocumentDbCacheAsync()
{
var kernel = GetKernelWithCache(services =>
{
services.AddCosmosMongoVectorStore(
TestConfiguration.CosmosMongo.ConnectionString,
TestConfiguration.CosmosMongo.DatabaseName);
services.AddDocumentDBVectorStore(
TestConfiguration.AzureDocumentDb.ConnectionString,
TestConfiguration.AzureDocumentDb.DatabaseName);
});
var result1 = await ExecuteAsync(kernel, "First run", "What's the tallest building in New York?");
@@ -293,7 +293,7 @@ public class SemanticCachingWithFilters(ITestOutputHelper output) : BaseTest(out
[VectorStoreData]
public string Result { get; set; }
[VectorStoreVector(Dimensions: 1536)]
[VectorStoreVector(1536)]
public ReadOnlyMemory<float> PromptEmbedding { get; set; }
}
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
namespace ChatCompletion;
#pragma warning disable SKEXP0010 // OpenAIPromptExecutionSettings.ExtraBody is experimental.
/// <summary>
/// <see cref="OpenAIPromptExecutionSettings.ExtraBody"/> is an escape hatch that injects additional fields
/// into the request body sent to the OpenAI-compatible endpoint. Use it to pass vendor-specific or preview
/// parameters that are not modeled by <see cref="OpenAIPromptExecutionSettings"/> (for example,
/// Qwen3's <c>enable_thinking</c> flag, ChatGLM thinking modes, or NVIDIA NIM custom knobs).
///
/// <para>Key syntax:</para>
/// <list type="bullet">
/// <item><description>A plain key (without leading <c>$.</c>) is treated as a literal top-level field name.</description></item>
/// <item><description>A key starting with <c>$.</c> is interpreted as a JSONPath expression and applied as a deep patch onto the request body.</description></item>
/// </list>
/// </summary>
public class OpenAI_ChatCompletionExtraBody(ITestOutputHelper output) : BaseTest(output)
{
/// <summary>
/// Adds a flat top-level field to the outgoing chat completion request:
/// <code>{ "messages": [...], "model": "qwen-plus", "enable_thinking": false, ... }</code>
/// </summary>
[Fact]
public async Task FlatFieldExampleAsync()
{
OpenAIChatCompletionService chatCompletionService = new(
TestConfiguration.OpenAI.ChatModelId,
TestConfiguration.OpenAI.ApiKey);
var settings = new OpenAIPromptExecutionSettings
{
ExtraBody = new Dictionary<string, object?>
{
// Required by Qwen3 open-source models for non-streaming calls.
["enable_thinking"] = false,
},
};
var chatHistory = new ChatHistory("You are a helpful assistant.");
chatHistory.AddUserMessage("Who are you?");
var reply = await chatCompletionService.GetChatMessageContentAsync(chatHistory, settings);
Console.WriteLine(reply.Content);
}
/// <summary>
/// Uses a <c>$.</c>-prefixed JSONPath key to surgically patch a nested field in the request body
/// (for example, into <c>thinking.enabled</c>). This avoids having to specify the entire nested object.
/// </summary>
[Fact]
public async Task DeepPatchExampleAsync()
{
OpenAIChatCompletionService chatCompletionService = new(
TestConfiguration.OpenAI.ChatModelId,
TestConfiguration.OpenAI.ApiKey);
var settings = new OpenAIPromptExecutionSettings
{
ExtraBody = new Dictionary<string, object?>
{
// Emits { "thinking": { "enabled": false } } in the request body.
["$.thinking.enabled"] = false,
},
};
var chatHistory = new ChatHistory("You are a helpful assistant.");
chatHistory.AddUserMessage("Summarize the plot of Hamlet in one sentence.");
var reply = await chatCompletionService.GetChatMessageContentAsync(chatHistory, settings);
Console.WriteLine(reply.Content);
}
}
@@ -12,8 +12,7 @@ namespace ChatCompletion;
/// <remarks>
/// Currently, web search is only supported with the following models:
/// <list type="bullet">
/// <item>gpt-4o-search-preview</item>
/// <item>gpt-4o-mini-search-preview</item>
/// <item>gpt-5-search-ap</item>
/// </list>
/// </remarks>
public class OpenAI_ChatCompletioWebSearch(ITestOutputHelper output) : BaseTest(output)
@@ -24,7 +23,7 @@ public class OpenAI_ChatCompletioWebSearch(ITestOutputHelper output) : BaseTest(
Assert.NotNull(TestConfiguration.OpenAI.ApiKey);
// Ensure you use a supported model
var modelId = "gpt-4o-mini-search-preview";
var modelId = "gpt-5-search-api";
var settings = new OpenAIPromptExecutionSettings
{
WebSearchOptions = new ChatWebSearchOptions()
+8 -11
View File
@@ -9,6 +9,8 @@
<IsTestProject>true</IsTestProject>
<!-- Suppress: "Declare types in namespaces", "Require ConfigureAwait", "Experimental" -->
<NoWarn>$(NoWarn);CS8618,IDE0009,IDE1006,CA1051,CA1050,CA1707,CA1054,CA2007,VSTHRD111,CS1591,RCS1110,RCS1243,CA5394,SKEXP0001,SKEXP0010,SKEXP0020,SKEXP0040,SKEXP0050,SKEXP0060,SKEXP0101,SKEXP0110,OPENAI001,CA1724,IDE1006,IDE0009,MEVD9000</NoWarn>
<!-- CommunityToolkit.VectorData.AzureCosmosDB pulls Microsoft.Azure.Cosmos which added a mandatory Newtonsoft.Json explicit-reference check; disable it since we don't use Newtonsoft.Json directly -->
<AzureCosmosDisableNewtonsoftJsonCheck>true</AzureCosmosDisableNewtonsoftJsonCheck>
<OutputType>Library</OutputType>
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
</PropertyGroup>
@@ -49,6 +51,12 @@
<PackageReference Include="AWSSDK.Core" />
<PackageReference Include="AWSSDK.SecurityToken" />
<PackageReference Include="Grpc.Net.ClientFactory" />
<PackageReference Include="CommunityToolkit.VectorData.AzureAISearch" />
<PackageReference Include="CommunityToolkit.VectorData.AzureDocumentDB" />
<PackageReference Include="CommunityToolkit.VectorData.InMemory" />
<PackageReference Include="CommunityToolkit.VectorData.Qdrant" />
<PackageReference Include="CommunityToolkit.VectorData.PgVector" />
<PackageReference Include="CommunityToolkit.VectorData.Redis" />
</ItemGroup>
<PropertyGroup>
@@ -71,17 +79,6 @@
<ProjectReference Include="..\..\src\Connectors\Connectors.Onnx\Connectors.Onnx.csproj" />
<ProjectReference Include="..\..\src\Connectors\Connectors.Ollama\Connectors.Ollama.csproj" />
<ProjectReference Include="..\..\src\Connectors\Connectors.OpenAI\Connectors.OpenAI.csproj" />
<ProjectReference Include="..\..\src\VectorData\AzureAISearch\AzureAISearch.csproj" />
<ProjectReference Include="..\..\src\VectorData\CosmosMongoDB\CosmosMongoDB.csproj" />
<ProjectReference Include="..\..\src\VectorData\Chroma\Chroma.csproj" />
<ProjectReference Include="..\..\src\VectorData\InMemory\InMemory.csproj" />
<ProjectReference Include="..\..\src\VectorData\MongoDB\MongoDB.csproj" />
<ProjectReference Include="..\..\src\VectorData\Pinecone\Pinecone.csproj" />
<ProjectReference Include="..\..\src\VectorData\PgVector\PgVector.csproj" />
<ProjectReference Include="..\..\src\VectorData\Qdrant\Qdrant.csproj" />
<ProjectReference Include="..\..\src\VectorData\Redis\Redis.csproj" />
<ProjectReference Include="..\..\src\VectorData\SqliteVec\SqliteVec.csproj" />
<ProjectReference Include="..\..\src\VectorData\Weaviate\Weaviate.csproj" />
<ProjectReference Include="..\..\src\Experimental\Orchestration.Flow\Experimental.Orchestration.Flow.csproj" />
<ProjectReference Include="..\..\src\Extensions\PromptTemplates.Handlebars\PromptTemplates.Handlebars.csproj" />
<ProjectReference Include="..\..\src\Extensions\PromptTemplates.Liquid\PromptTemplates.Liquid.csproj" />
@@ -253,7 +253,7 @@ public class LocalExamplePlugin(ITestOutputHelper output)
[KernelFunction]
public async Task<string> TaskInjectingCancellationTokenWithStringResult(CancellationToken cancellationToken)
{
var result = $"Cancellation resquested: {cancellationToken.IsCancellationRequested}";
var result = $"Cancellation requested: {cancellationToken.IsCancellationRequested}";
this._output.WriteLine($"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected Cancellation Token -> result: {result}");
return result;
}
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;
using CommunityToolkit.VectorData.InMemory;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.HuggingFace;
using Microsoft.SemanticKernel.Connectors.SqliteVec;
using Microsoft.SemanticKernel.Embeddings;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
@@ -32,12 +32,11 @@ public class HuggingFace_TextEmbeddingCustomHttpHandler(ITestOutputHelper output
})
);
var sqliteCollection = new SqliteCollection<string, Record>(
"Data Source=./../../../Sqlite.sqlite",
var inMemoryCollection = new InMemoryCollection<string, Record>(
name: "Test",
new() { EmbeddingGenerator = hf.AsEmbeddingGenerator() });
await sqliteCollection.UpsertAsync(new Record
await inMemoryCollection.UpsertAsync(new Record
{
Id = "1",
Text = "THIS IS A SAMPLE",
@@ -53,7 +52,7 @@ public class HuggingFace_TextEmbeddingCustomHttpHandler(ITestOutputHelper output
[VectorStoreData]
public string Text { get; set; }
[VectorStoreVector(Dimensions: 768)]
[VectorStoreVector(768)]
public string Embedding { get; set; }
}
@@ -127,7 +127,7 @@ Jane: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, nunc
Jane: Darn, it's just repeating stuff now.
John: I think we're done.
Jane: We're not though! We need like 1500 more characters.
John: Oh Cananda, our home and native land.
John: Oh Canada, our home and native land.
Jane: True patriot love in all thy sons command.
John: With glowing hearts we see thee rise.
Jane: The True North strong and free.
@@ -1,87 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.Pinecone;
using Pinecone;
namespace Memory.VectorStoreLangchainInterop;
/// <summary>
/// Contains a factory method that can be used to create a Pinecone vector store that is compatible with datasets ingested using Langchain.
/// </summary>
/// <remarks>
/// This class is used with the <see cref="VectorStore_Langchain_Interop"/> sample.
/// </remarks>
public static class PineconeFactory
{
/// <summary>
/// Record definition that matches the storage format used by Langchain for Pinecone.
/// </summary>
private static readonly VectorStoreCollectionDefinition s_definition = new()
{
Properties =
[
new VectorStoreKeyProperty("Key", typeof(string)),
new VectorStoreDataProperty("Content", typeof(string)) { StorageName = "text" },
new VectorStoreDataProperty("Source", typeof(string)) { StorageName = "source" },
new VectorStoreVectorProperty("Embedding", typeof(ReadOnlyMemory<float>), 1536) { StorageName = "embedding" }
]
};
/// <summary>
/// Create a new Pinecone-backed <see cref="VectorStore"/> that can be used to read data that was ingested using Langchain.
/// </summary>
/// <param name="pineconeClient">Pinecone client that can be used to manage the collections and points in a Pinecone store.</param>
/// <returns>The <see cref="VectorStore"/>.</returns>
public static VectorStore CreatePineconeLangchainInteropVectorStore(PineconeClient pineconeClient)
=> new PineconeLangchainInteropVectorStore(new PineconeVectorStore(pineconeClient), pineconeClient);
private sealed class PineconeLangchainInteropVectorStore(
VectorStore innerStore,
PineconeClient pineconeClient)
: VectorStore
{
private readonly PineconeClient _pineconeClient = pineconeClient;
public override VectorStoreCollection<TKey, TRecord> GetCollection<TKey, TRecord>(string name, VectorStoreCollectionDefinition? definition = null)
{
if (typeof(TKey) != typeof(string) || typeof(TRecord) != typeof(LangchainDocument<string>))
{
throw new NotSupportedException("This VectorStore is only usable with string keys and LangchainDocument<string> record types");
}
// Create a Pinecone collection and pass in our custom record definition that matches
// the schema used by Langchain so that the default mapper can use the storage names
// in it, to map to the storage scheme.
return (new PineconeCollection<TKey, TRecord>(
_pineconeClient,
name,
new()
{
Definition = s_definition
}) as VectorStoreCollection<TKey, TRecord>)!;
}
public override VectorStoreCollection<object, Dictionary<string, object?>> GetDynamicCollection(string name, VectorStoreCollectionDefinition? definition = null)
{
// Create a Pinecone collection and pass in our custom record definition that matches
// the schema used by Langchain so that the default mapper can use the storage names
// in it, to map to the storage scheme.
return new PineconeDynamicCollection(
_pineconeClient,
name,
new()
{
Definition = s_definition
});
}
public override object? GetService(Type serviceType, object? serviceKey = null) => innerStore.GetService(serviceType, serviceKey);
public override IAsyncEnumerable<string> ListCollectionNamesAsync(CancellationToken cancellationToken = default) => innerStore.ListCollectionNamesAsync(cancellationToken);
public override Task<bool> CollectionExistsAsync(string name, CancellationToken cancellationToken = default) => innerStore.CollectionExistsAsync(name, cancellationToken);
public override Task EnsureCollectionDeletedAsync(string name, CancellationToken cancellationToken = default) => innerStore.EnsureCollectionDeletedAsync(name, cancellationToken);
}
}
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using CommunityToolkit.VectorData.Redis;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.Redis;
using StackExchange.Redis;
namespace Memory.VectorStoreLangchainInterop;

Some files were not shown because too many files have changed in this diff Show More