Skip to content

Commit 03e12d4

Browse files
authored
Merge branch 'main' into feat/respect-function-choice-filters
2 parents d3148ff + 2435461 commit 03e12d4

File tree

1,347 files changed

+56241
-29225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,347 files changed

+56241
-29225
lines changed

.devcontainer/devcontainer.json

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,23 @@
22
"image": "mcr.microsoft.com/devcontainers/universal:2",
33
"features": {
44
"ghcr.io/devcontainers/features/node:1": {},
5-
"ghcr.io/devcontainers/features/dotnet:1": {
6-
"version": "8"
5+
"ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": {},
6+
"ghcr.io/devcontainers/features/github-cli:1": {
7+
"version": "2"
78
},
8-
"ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": {}
9+
"ghcr.io/devcontainers/features/powershell:1": {
10+
"version": "latest"
11+
},
12+
"ghcr.io/azure/azure-dev/azd:0": {
13+
"version": "latest"
14+
},
15+
"ghcr.io/devcontainers/features/common-utils:2": {},
16+
"ghcr.io/devcontainers/features/dotnet:2": {
17+
"version": "none",
18+
"dotnetRuntimeVersions": "10.0",
19+
"aspNetCoreRuntimeVersions": "10.0"
20+
},
21+
"ghcr.io/devcontainers/features/copilot-cli:1": {}
922
},
1023
"customizations": {
1124
"vscode": {

.github/upgrades/prompts/SemanticKernelToAgentFramework.md

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,73 @@ AIAgent agent = chatClient.CreateAIAgent(
384384
7. Pass tools directly to agent creation method
385385
</configuration_changes>
386386

387+
### Runtime Tool Registration Transformation
388+
389+
<configuration_changes>
390+
In Semantic Kernel, plugins/tools could be added to the kernel after it was already built using `kernel.Plugins.Add()`. Agent Framework provides a similar capability using the builder middleware API.
391+
392+
**Replace this Semantic Kernel post-creation tool registration pattern:**
393+
```csharp
394+
// Define the tool function
395+
[Description("Get the weather for a location")]
396+
static string GetWeather(string location) => $"Weather in {location}";
397+
398+
// Semantic Kernel - Tools added after kernel is already built
399+
Kernel kernel = kernelBuilder.Build();
400+
ChatCompletionAgent agent = new() { Kernel = kernel };
401+
402+
// Later: Add tools to the existing kernel instance
403+
KernelFunction function = KernelFunctionFactory.CreateFromMethod(GetWeather);
404+
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("WeatherPlugin", [function]);
405+
kernel.Plugins.Add(plugin);
406+
407+
// Tools are now available on subsequent invocations
408+
await foreach (var item in agent.InvokeAsync(userInput, thread)) { ... }
409+
```
410+
411+
**With this Agent Framework pattern using builder middleware:**
412+
```csharp
413+
// Define the tool function
414+
[Description("Get the weather for a location")]
415+
static string GetWeather(string location) => $"Weather in {location}";
416+
417+
// Start with an existing agent
418+
AIAgent existingAgent = chatClient.CreateAIAgent(
419+
instructions: "You are a helpful assistant");
420+
421+
// Create an augmented agent with additional tools using builder middleware
422+
var augmentedAgent = existingAgent.AsBuilder()
423+
.Use(async (chatMessages, agentThread, agentRunOptions, next, cancellationToken) =>
424+
{
425+
if (agentRunOptions is ChatClientAgentRunOptions chatClientAgentRunOptions)
426+
{
427+
chatClientAgentRunOptions.ChatOptions ??= new ChatOptions();
428+
chatClientAgentRunOptions.ChatOptions.Tools ??= [];
429+
chatClientAgentRunOptions.ChatOptions.Tools.Add(AIFunctionFactory.Create(GetWeather));
430+
}
431+
432+
return await next(chatMessages, agentThread, agentRunOptions, cancellationToken);
433+
})
434+
.Build();
435+
436+
// Use the augmented agent with the additional tools
437+
AgentRunResponse result = await augmentedAgent.RunAsync(userInput, thread);
438+
```
439+
440+
**Required changes:**
441+
1. Call `AsBuilder()` on the existing agent to get a builder
442+
2. Use the `Use()` middleware method to intercept and modify run options
443+
3. Add tools to `ChatClientAgentRunOptions.ChatOptions.Tools` in the middleware
444+
4. Call `Build()` to create the augmented agent instance
445+
5. Use the new augmented agent for invocations that need the additional tools
446+
447+
**Note:** This pattern is the preferred approach as it provides:
448+
- A controlled environment with a dedicated agent instance
449+
- No disruption to existing agent usages
450+
- Dynamic tool composition per user, tenant, or feature flags
451+
- Modular system composition without recreating agents
452+
</configuration_changes>
453+
387454
### Invocation Method Transformation
388455

389456
<api_changes>
@@ -803,20 +870,16 @@ var agentOptions = new ChatClientAgentRunOptions(new ChatOptions
803870
{
804871
MaxOutputTokens = 8000,
805872
// Breaking glass to access provider-specific options
806-
RawRepresentationFactory = (_) => new OpenAI.Responses.ResponseCreationOptions()
873+
RawRepresentationFactory = (_) => new OpenAI.Responses.CreateResponseOptions()
807874
{
808-
ReasoningOptions = new()
809-
{
810-
ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.High,
811-
ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
812-
}
875+
TruncationMode = OpenAI.Responses.ResponseTruncationMode.Auto,
813876
}
814877
});
815878
```
816879

817880
**Use this pattern when:**
818881
1. Standard `ChatOptions` properties don't cover required model settings
819-
2. Provider-specific configuration is needed (e.g., reasoning effort level)
882+
2. Provider-specific configuration is needed (e.g., truncation mode)
820883
3. Advanced SDK features need to be accessed
821884
</configuration_changes>
822885

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: DevFlow PR Review
2+
3+
on:
4+
pull_request_target:
5+
types:
6+
- opened
7+
- reopened
8+
- ready_for_review
9+
workflow_dispatch:
10+
inputs:
11+
pr_number:
12+
description: Pull request number to review
13+
required: true
14+
type: string
15+
16+
permissions:
17+
contents: read
18+
issues: write
19+
pull-requests: write
20+
21+
concurrency:
22+
group: devflow-pr-review-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
23+
cancel-in-progress: true
24+
25+
env:
26+
DEVFLOW_REPOSITORY: ${{ vars.DF_REPO }}
27+
DEVFLOW_REF: main
28+
TARGET_REPO_PATH: ${{ github.workspace }}/target-repo
29+
DEVFLOW_PATH: ${{ github.workspace }}/devflow
30+
31+
jobs:
32+
review:
33+
runs-on: ubuntu-latest
34+
timeout-minutes: 60
35+
if: ${{ github.event_name != 'pull_request_target' || !github.event.pull_request.draft }}
36+
37+
steps:
38+
- name: Resolve PR metadata
39+
id: pr
40+
shell: bash
41+
env:
42+
PR_HTML_URL: ${{ github.event.pull_request.html_url }}
43+
PR_NUMBER_EVENT: ${{ github.event.pull_request.number }}
44+
PR_NUMBER_INPUT: ${{ inputs.pr_number }}
45+
run: |
46+
set -euo pipefail
47+
48+
if [[ "${GITHUB_EVENT_NAME}" == "pull_request_target" ]]; then
49+
pr_number="${PR_NUMBER_EVENT}"
50+
pr_url="${PR_HTML_URL}"
51+
else
52+
pr_number="${PR_NUMBER_INPUT}"
53+
pr_url="https://github.com/${GITHUB_REPOSITORY}/pull/${pr_number}"
54+
fi
55+
56+
if [[ ! "$pr_number" =~ ^[1-9][0-9]*$ ]]; then
57+
echo "Could not determine PR number; for workflow_dispatch runs, the 'pr_number' input is required when not running on pull_request_target." >&2
58+
exit 1
59+
fi
60+
61+
echo "pr_url=${pr_url}" >> "$GITHUB_OUTPUT"
62+
echo "pr_number=${pr_number}" >> "$GITHUB_OUTPUT"
63+
echo "repo=${GITHUB_REPOSITORY}" >> "$GITHUB_OUTPUT"
64+
65+
# Safe checkout: base repo only, not the untrusted PR head.
66+
- name: Checkout target repo base
67+
uses: actions/checkout@v5
68+
with:
69+
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.base.sha || github.sha }}
70+
fetch-depth: 0
71+
persist-credentials: false
72+
path: target-repo
73+
74+
# Private DevFlow checkout: the PAT/token grants access to this repo's code.
75+
- name: Checkout DevFlow
76+
uses: actions/checkout@v5
77+
with:
78+
repository: ${{ env.DEVFLOW_REPOSITORY }}
79+
ref: ${{ env.DEVFLOW_REF }}
80+
token: ${{ secrets.DEVFLOW_TOKEN }}
81+
fetch-depth: 1
82+
persist-credentials: false
83+
path: devflow
84+
85+
- name: Set up Python
86+
uses: actions/setup-python@v5
87+
with:
88+
python-version: "3.13"
89+
90+
- name: Set up uv
91+
uses: astral-sh/setup-uv@v6
92+
with:
93+
version: "0.5.x"
94+
enable-cache: true
95+
96+
- name: Install DevFlow dependencies
97+
working-directory: ${{ env.DEVFLOW_PATH }}
98+
run: uv sync --frozen
99+
100+
- name: Classify PR relevance
101+
id: spam
102+
working-directory: ${{ env.DEVFLOW_PATH }}
103+
env:
104+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105+
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
106+
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
107+
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
108+
PR_REPO: ${{ steps.pr.outputs.repo }}
109+
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
110+
run: |
111+
uv run python scripts/classify_pr_spam.py \
112+
--repo "$PR_REPO" \
113+
--pr-number "$PR_NUMBER" \
114+
--repo-path "${TARGET_REPO_PATH}" \
115+
--apply-labels
116+
117+
- name: Stop after spam gate
118+
if: ${{ steps.spam.outputs.decision != 'allow' }}
119+
shell: bash
120+
env:
121+
SPAM_DECISION: ${{ steps.spam.outputs.decision }}
122+
run: |
123+
echo "Skipping review because spam gate decided: ${SPAM_DECISION}"
124+
125+
- name: Run PR review
126+
if: ${{ steps.spam.outputs.decision == 'allow' }}
127+
id: review
128+
working-directory: ${{ env.DEVFLOW_PATH }}
129+
env:
130+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131+
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
132+
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
133+
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
134+
PR_URL: ${{ steps.pr.outputs.pr_url }}
135+
run: |
136+
uv run python scripts/trigger_pr_review.py \
137+
--pr-url "$PR_URL" \
138+
--github-username "$GITHUB_ACTOR" \
139+
--no-require-comment-selection

.github/workflows/dotnet-build-and-test.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ jobs:
5757
matrix:
5858
include:
5959
- {
60-
dotnet: "8.0",
60+
dotnet: "10.0",
6161
os: "ubuntu-latest",
6262
configuration: Release,
6363
integration-tests: true,
6464
environment: "integration",
6565
}
66-
- { dotnet: "8.0", os: "windows-latest", configuration: Debug }
67-
- { dotnet: "8.0", os: "windows-latest", configuration: Release }
66+
- { dotnet: "10.0", os: "windows-latest", configuration: Debug }
67+
- { dotnet: "9.0", os: "windows-latest", configuration: Release }
6868

6969
runs-on: ${{ matrix.os }}
7070
environment: ${{ matrix.environment }}
@@ -74,7 +74,7 @@ jobs:
7474
persist-credentials: false
7575

7676
- name: Setup dotnet
77-
uses: actions/setup-dotnet@v4.3.1
77+
uses: actions/setup-dotnet@v5
7878
with:
7979
global-json-file: ${{ github.workspace }}/dotnet/global.json
8080

@@ -138,7 +138,7 @@ jobs:
138138
run: |
139139
export INTEGRATION_TEST_PROJECTS=$(find ./dotnet -type f -name "*IntegrationTests.csproj" | grep -v "Experimental.Orchestration.Flow.IntegrationTests.csproj" | grep -v "VectorDataIntegrationTests.csproj" | tr '\n' ' ')
140140
for project in $INTEGRATION_TEST_PROJECTS; do
141-
dotnet test -f net8.0 -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx
141+
dotnet test -f net10.0 -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx
142142
done
143143
env:
144144
# Azure OpenAI Deployments

.github/workflows/dotnet-ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
include:
22-
- { os: ubuntu-latest, dotnet: '8.0', configuration: Debug }
23-
- { os: ubuntu-latest, dotnet: '8.0', configuration: Release }
22+
- { os: ubuntu-latest, dotnet: '10.0', configuration: Debug }
23+
- { os: ubuntu-latest, dotnet: '10.0', configuration: Release }
2424

2525
runs-on: ${{ matrix.os }}
2626
steps:
@@ -67,7 +67,7 @@ jobs:
6767
matrix:
6868
os: [windows-latest]
6969
configuration: [Release, Debug]
70-
dotnet-version: ['8.0.x']
70+
dotnet-version: ['10.0.x']
7171
runs-on: ${{ matrix.os }}
7272
env:
7373
NUGET_CERT_REVOCATION_MODE: offline
@@ -78,7 +78,7 @@ jobs:
7878
persist-credentials: false
7979

8080
- name: Setup .NET SDK ${{ matrix.dotnet-version }}
81-
uses: actions/setup-dotnet@v4
81+
uses: actions/setup-dotnet@v5
8282
with:
8383
dotnet-version: ${{ matrix.dotnet-version }}
8484
env:

.github/workflows/dotnet-format.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
fail-fast: false
2626
matrix:
2727
include:
28-
- { dotnet: "9.0", configuration: Release, os: ubuntu-latest }
28+
- { dotnet: "10.0", configuration: Release, os: ubuntu-latest }
2929

3030
runs-on: ${{ matrix.os }}
3131
env:

.github/workflows/dotnet-integration-tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ jobs:
2929
persist-credentials: false
3030

3131
- name: Setup .NET
32-
uses: actions/setup-dotnet@v4
32+
uses: actions/setup-dotnet@v5
3333
if: ${{ github.event_name != 'pull_request' }}
3434
with:
35-
dotnet-version: 8.0.x
35+
dotnet-version: 10.0.x
3636

3737
- name: Find projects
3838
shell: bash

0 commit comments

Comments
 (0)