From b35977ce564e5a6e013cfb6836299685d2c0a899 Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Tue, 19 Nov 2024 17:36:08 -0800 Subject: [PATCH 01/12] [MAYBE MERGE BEFORE WE TEST ESRP] Set up ADO pipeline for real-signing && nightly build (#4270) * add ado pipeline * update * update pipeline * update * update iamge * update sln * install aspire workload * Aspire -> aspire * pin code analysis version to 4.8.0 * update pack * set up wordir * update * update * update * clean up * update * clean up * add dotnet --- .azure/pipelines/build.yaml | 91 ++++++++++ .azure/pipelines/templates/build.yaml | 244 ++++++++++++++++++++++++++ .azure/pipelines/templates/vars.yaml | 34 ++++ dotnet/Directory.Packages.props | 2 +- 4 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 .azure/pipelines/build.yaml create mode 100644 .azure/pipelines/templates/build.yaml create mode 100644 .azure/pipelines/templates/vars.yaml diff --git a/.azure/pipelines/build.yaml b/.azure/pipelines/build.yaml new file mode 100644 index 000000000000..0f6a55e2958e --- /dev/null +++ b/.azure/pipelines/build.yaml @@ -0,0 +1,91 @@ +trigger: + branches: + include: + - main + paths: + exclude: + - samples + +schedules: +- cron: "0 0 * * *" + displayName: 'Daily midnight build (including CodeQL)' + branches: + include: + - main + - 3.x + always: true + +parameters: + - name: build_configuration + displayName: Build configuration + type: string + default: Release + values: + - Release + - Debug + - name: version_prefix + displayName: Version prefix + type: string + default: 8.0.0 + - name: include_suffix + displayName: Append version suffix + type: boolean + default: true + - name: version_suffix + displayName: Version suffix + type: string + default: ci.$(Build.BuildNumber) + - name: codesign + displayName: Enable code signing + type: boolean + default: false + - name: skip_test + displayName: Skip tests + type: boolean + default: false + - name: publish_nuget + displayName: Publish to nuget.org + type: boolean + default: false + - name: runCodeQL3000 + default: false + displayName: Run CodeQL3000 tasks + type: boolean + +variables: +- template: templates/vars.yaml + +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + ${{ if eq(variables['System.TeamProject'], 'GitHub - PR Builds') }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates + ${{ else }}: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + settings: + skipBuildTagsForGitHubPullRequests: true + pool: + name: $(pool_name) + image: $(pool_image) + os: windows + stages: + - stage: build_test + displayName: Build and Tests + jobs: + - template: /.azure/pipelines/templates/build.yaml@self + parameters: + build_configuration: ${{ parameters.build_configuration }} + version_prefix: ${{ parameters.version_prefix }} + include_suffix: ${{ parameters.include_suffix }} + version_suffix: ${{ parameters.version_suffix }} + codesign: ${{ parameters.codesign }} + skip_test: ${{ parameters.skip_test }} + publish_nightly: false + publish_nuget: ${{ parameters.publish_nuget }} + runCodeQL3000: ${{ parameters.runCodeQL3000 }} \ No newline at end of file diff --git a/.azure/pipelines/templates/build.yaml b/.azure/pipelines/templates/build.yaml new file mode 100644 index 000000000000..47714e137d74 --- /dev/null +++ b/.azure/pipelines/templates/build.yaml @@ -0,0 +1,244 @@ +parameters: + - name: build_configuration + displayName: Build configuration + type: string + default: Release + values: + - Release + - Debug + - name: version_prefix + displayName: Version prefix + type: string + default: 8.0.0 + - name: include_suffix + displayName: Append version suffix + type: boolean + default: true + - name: version_suffix + displayName: Version suffix + type: string + default: ci.$(Build.BuildNumber) + - name: codesign + displayName: Enable code signing + type: boolean + default: false + - name: skip_test + displayName: Skip tests + type: boolean + default: false + - name: publish_nightly + displayName: Publish to autogen-nightly + type: boolean + default: false + - name: publish_nuget + displayName: Publish to nuget.org + type: boolean + default: false + - name: runCodeQL3000 + default: false + displayName: Run CodeQL3000 tasks + type: boolean + +jobs: + +# Build, sign dlls, build nuget pkgs, then sign them +- job: Build + displayName: Build and create NuGet packages + variables: + ${{ if eq(parameters.codesign, true) }}: + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + esrp_signing: false + microbuild_signing: true + publishVstsFeed: 'public/orleans-nightly' + ${{ else }}: + esrp_signing: true + microbuild_signing: false + publishVstsFeed: 'orleans-public/orleans-nightly' + ${{ else }}: + esrp_signing: false + microbuild_signing: false + ${{ if ne(variables['System.TeamProject'], 'GitHub - PR Builds') }}: + templateContext: + outputs: + - output: pipelineArtifact + targetPath: '$(build.sourcesdirectory)/dotnet/artifacts' + artifactName: artifacts folder + # Publish packages to nightly + - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nightly, true)) }}: + - output: nuget + useDotNetTask: false + packageParentPath: $(Pipeline.Workspace) + packagesToPush: $(build.sourcesdirectory)/artifacts/${{parameters.build_configuration}}/**/*.nupkg + nuGetFeedType: internal + publishVstsFeed: $(publishVstsFeed) + allowPackageConflicts: true + - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nuget, true)) }}: + - output: nuget + condition: succeeded() + useDotNetTask: false + packageParentPath: $(Pipeline.Workspace) + packagesToPush: $(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}/**/*.nupkg + nuGetFeedType: external + publishFeedCredentials: dotnet-orleans-nuget + publishPackageMetadata: true + allowPackageConflicts: true + steps: + - ${{ if eq(variables.microbuild_signing, true) }}: + - task: MicroBuildSigningPlugin@4 + displayName: Install MicroBuild plugin + inputs: + signType: real + zipSources: false + feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json + env: + TeamName: AutoGen + MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' + - checkout: self + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + useGlobalJson: true + workingDirectory: $(Build.SourcesDirectory)/dotnet + - task: Bash@3 + displayName: Install .NET Aspire workload + inputs: + targetType: 'inline' + script: | + dotnet nuget locals all --clear + dotnet workload install aspire + - ${{ if eq(variables.runCodeQL3000, 'true') }}: + - task: CodeQL3000Init@0 + displayName: CodeQL Initialize + # This task only tags a build if it actually does CodeQL3000 work. + # Those tasks no-op while the analysis is considered up to date i.e. for runs w/in a few days of each other. + - script: "echo ##vso[build.addbuildtag]CodeQL3000" + displayName: 'Set CI CodeQL3000 tag' + condition: ne(variables.CODEQL_DIST,'') + - task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + arguments: '$(build_flags) /bl:${{parameters.build_configuration}}-Build.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)' + workingDirectory: $(Build.SourcesDirectory)/dotnet + env: + VersionPrefix: ${{parameters.version_prefix}} + ${{ if eq(parameters.include_suffix, true) }}: + VersionSuffix: ${{parameters.version_suffix}} + OfficialBuild: $(official_build) + - ${{ if eq(variables.runCodeQL3000, 'true') }}: + - task: CodeQL3000Finalize@0 + displayName: CodeQL Finalize + # DLL code signing + - ${{ if eq(variables.esrp_signing, true) }}: + - task: UseDotNet@2 + displayName: 'Codesign: Use .NET Core' + inputs: + packageType: runtime + version: $(codesign_runtime) + - task: CopyFiles@2 + displayName: 'Codesign: Copy Files for signing' + inputs: + SourceFolder: '$(build.sourcesdirectory)' + Contents: | + src/**/bin/${{parameters.build_configuration}}/**/AutoGen*.dll + src/**/bin/${{parameters.build_configuration}}/**/Microsoft.AutoGen.*.dll + TargetFolder: '$(build.artifactstagingdirectory)\codesign' + CleanTargetFolder: true + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'Codesign: ESRP CodeSigning' + inputs: + ConnectedServiceName: 'CodeSign Service (NuGet)' + FolderPath: '$(build.artifactstagingdirectory)\codesign' + Pattern: '*' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd \"SHA256\"" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 180 + VerboseLogin: true + - task: CopyFiles@2 + displayName: 'Codesign: Copy Signed Files Back' + inputs: + SourceFolder: '$(build.artifactstagingdirectory)\codesign' + Contents: '**\*' + TargetFolder: '$(build.sourcesdirectory)' + OverWrite: true + # End DLL code signing + - task: CmdLine@2 + displayName: Pack + inputs: + script: 'dotnet pack --no-build --no-restore $(build_flags) /bl:${{parameters.build_configuration}}-Pack.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)' + workingDirectory: $(Build.SourcesDirectory)/dotnet + env: + VersionPrefix: ${{parameters.version_prefix}} + ${{ if eq(parameters.include_suffix, true) }}: + VersionSuffix: ${{parameters.version_suffix}} + OfficialBuild: $(official_build) + # NuGet code signing + - ${{ if eq(variables.esrp_signing, true) }}: + - task: UseDotNet@2 + displayName: 'Codesign: Use .NET Core' + inputs: + packageType: runtime + version: $(codesign_runtime) + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 + displayName: 'Codesign: ESRP CodeSigning (nuget)' + inputs: + ConnectedServiceName: 'CodeSign Service (NuGet)' + FolderPath: '$(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}' + Pattern: '*.nupkg' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetSign", + "parameters": [], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + SessionTimeout: 180 + VerboseLogin: true diff --git a/.azure/pipelines/templates/vars.yaml b/.azure/pipelines/templates/vars.yaml new file mode 100644 index 000000000000..0b735a02500f --- /dev/null +++ b/.azure/pipelines/templates/vars.yaml @@ -0,0 +1,34 @@ +# It seems that variables must be defined in their own file when using templates + +variables: + build_flags: ' /m /v:m' + solution: 'AutoGen.sln' + codesign_runtime: '2.1.x' + GDN_SUPPRESS_FORKED_BUILD_WARNING: true # Avoid warning "Guardian is not supported for builds from forked GitHub repositories" + MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' + # Auto-injection is not necessary because the tasks are explicitly included where they're enabled. + Codeql.SkipTaskAutoInjection: true + ${{ if eq(variables['System.TeamProject'], 'GitHub - PR Builds') }}: + pool_name: '1es-agpublish-pool' + pool_image: 'agpublish-agent-image' + official_build: false + ${{ else }}: + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + pool_name: '1es-agpublish-pool' + pool_image: 'agpublish-agent-image' + ${{ else }}: + pool_name: '1es-agpublish-pool' + pool_image: 'agpublish-agent-image' + official_build: true + # Do not let CodeQL3000 Extension gate scan frequency. + Codeql.Cadence: 0 + # Enable CodeQL3000 unconditionally so it may be run on any branch. + Codeql.Enabled: true + # Ignore test and infrastructure code. + Codeql.SourceRoot: src + # CodeQL3000 needs this plumbed along as a variable to enable TSA. Don't use TSA in manual builds. + Codeql.TSAEnabled: ${{ eq(variables['Build.Reason'], 'Schedule') }} + # Default expects tsaoptions.json under SourceRoot. + Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json' + # Do not slow builds down w/ the CodeQL3000 tasks unless this is a nightly build or it's requested. + runCodeQL3000: ${{ or(eq(variables['Build.Reason'], 'Schedule'), and(eq(variables['Build.Reason'], 'Manual'), eq(parameters.runCodeQL3000, 'true'))) }} \ No newline at end of file diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 5321860e427f..0f6ecd10b1d9 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -106,8 +106,8 @@ + - From 611666c00dbff5d77aad9db36381f3bc6e4e11d9 Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 08:52:39 -0800 Subject: [PATCH 02/12] .NET Update ADO to publish to nightly build for every CI build (#4275) --- .azure/pipelines/build.yaml | 11 ++++---- .azure/pipelines/templates/build.yaml | 38 ++++++--------------------- 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/.azure/pipelines/build.yaml b/.azure/pipelines/build.yaml index 0f6a55e2958e..3d25dfa920a4 100644 --- a/.azure/pipelines/build.yaml +++ b/.azure/pipelines/build.yaml @@ -23,10 +23,6 @@ parameters: values: - Release - Debug - - name: version_prefix - displayName: Version prefix - type: string - default: 8.0.0 - name: include_suffix displayName: Append version suffix type: boolean @@ -47,6 +43,10 @@ parameters: displayName: Publish to nuget.org type: boolean default: false + - name: publish_nightly + displayName: Publish to autogen-nightly + type: boolean + default: false - name: runCodeQL3000 default: false displayName: Run CodeQL3000 tasks @@ -81,11 +81,10 @@ extends: - template: /.azure/pipelines/templates/build.yaml@self parameters: build_configuration: ${{ parameters.build_configuration }} - version_prefix: ${{ parameters.version_prefix }} include_suffix: ${{ parameters.include_suffix }} version_suffix: ${{ parameters.version_suffix }} codesign: ${{ parameters.codesign }} skip_test: ${{ parameters.skip_test }} - publish_nightly: false + publish_nightly: ${{ parameters.publish_nightly }} publish_nuget: ${{ parameters.publish_nuget }} runCodeQL3000: ${{ parameters.runCodeQL3000 }} \ No newline at end of file diff --git a/.azure/pipelines/templates/build.yaml b/.azure/pipelines/templates/build.yaml index 47714e137d74..7e3d82f4d678 100644 --- a/.azure/pipelines/templates/build.yaml +++ b/.azure/pipelines/templates/build.yaml @@ -6,10 +6,6 @@ parameters: values: - Release - Debug - - name: version_prefix - displayName: Version prefix - type: string - default: 8.0.0 - name: include_suffix displayName: Append version suffix type: boolean @@ -45,18 +41,11 @@ jobs: - job: Build displayName: Build and create NuGet packages variables: + publishVstsFeed: 'AGPublic/AutoGen-Nightly' ${{ if eq(parameters.codesign, true) }}: - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - esrp_signing: false - microbuild_signing: true - publishVstsFeed: 'public/orleans-nightly' - ${{ else }}: - esrp_signing: true - microbuild_signing: false - publishVstsFeed: 'orleans-public/orleans-nightly' + esrp_signing: true ${{ else }}: esrp_signing: false - microbuild_signing: false ${{ if ne(variables['System.TeamProject'], 'GitHub - PR Builds') }}: templateContext: outputs: @@ -64,11 +53,11 @@ jobs: targetPath: '$(build.sourcesdirectory)/dotnet/artifacts' artifactName: artifacts folder # Publish packages to nightly - - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nightly, true)) }}: + - ${{ if eq(parameters.publish_nightly, true) }}: # TODO add eq(parameters.codesign, true) - output: nuget useDotNetTask: false packageParentPath: $(Pipeline.Workspace) - packagesToPush: $(build.sourcesdirectory)/artifacts/${{parameters.build_configuration}}/**/*.nupkg + packagesToPush: $(build.sourcesdirectory)/dotnet/artifacts/**/*.nupkg;$(build.sourcesdirectory)/dotnet/artifacts/**/*.snupkg nuGetFeedType: internal publishVstsFeed: $(publishVstsFeed) allowPackageConflicts: true @@ -77,22 +66,12 @@ jobs: condition: succeeded() useDotNetTask: false packageParentPath: $(Pipeline.Workspace) - packagesToPush: $(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}/**/*.nupkg + packagesToPush: $(build.sourcesdirectory)/dotnet/artifacts/**/*.nupkg;$(build.sourcesdirectory)/dotnet/artifacts/**/*.snupkg nuGetFeedType: external publishFeedCredentials: dotnet-orleans-nuget publishPackageMetadata: true allowPackageConflicts: true steps: - - ${{ if eq(variables.microbuild_signing, true) }}: - - task: MicroBuildSigningPlugin@4 - displayName: Install MicroBuild plugin - inputs: - signType: real - zipSources: false - feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - env: - TeamName: AutoGen - MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' - checkout: self - task: UseDotNet@2 displayName: 'Use .NET Core sdk' @@ -121,10 +100,10 @@ jobs: arguments: '$(build_flags) /bl:${{parameters.build_configuration}}-Build.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)' workingDirectory: $(Build.SourcesDirectory)/dotnet env: - VersionPrefix: ${{parameters.version_prefix}} - ${{ if eq(parameters.include_suffix, true) }}: + ${{ if and(eq(parameters.include_suffix, true), eq(parameters.publish_nuget, false)) }}: VersionSuffix: ${{parameters.version_suffix}} OfficialBuild: $(official_build) + - ${{ if eq(variables.runCodeQL3000, 'true') }}: - task: CodeQL3000Finalize@0 displayName: CodeQL Finalize @@ -205,8 +184,7 @@ jobs: script: 'dotnet pack --no-build --no-restore $(build_flags) /bl:${{parameters.build_configuration}}-Pack.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)' workingDirectory: $(Build.SourcesDirectory)/dotnet env: - VersionPrefix: ${{parameters.version_prefix}} - ${{ if eq(parameters.include_suffix, true) }}: + ${{ if and(eq(parameters.include_suffix, true), eq(parameters.publish_nuget, false)) }}: VersionSuffix: ${{parameters.version_suffix}} OfficialBuild: $(official_build) # NuGet code signing From 8593b7df9f94d0b6d491f78899262ae69d23ac37 Mon Sep 17 00:00:00 2001 From: Gerardo Moreno Date: Wed, 20 Nov 2024 09:34:13 -0800 Subject: [PATCH 03/12] Console to return last processed message (#4279) * Console to return last processed (#4277) * Preserve input generator type * Add tests * format --------- Co-authored-by: Jack Gerrits Co-authored-by: Eric Zhu --- .../src/autogen_agentchat/task/_console.py | 34 ++++++++++++--- .../tests/test_group_chat.py | 41 ++++++++++++++++++- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/task/_console.py b/python/packages/autogen-agentchat/src/autogen_agentchat/task/_console.py index 3c6464b1f07f..6b5849e4cf4b 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/task/_console.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/task/_console.py @@ -1,7 +1,7 @@ import os import sys import time -from typing import AsyncGenerator, List +from typing import AsyncGenerator, List, Optional, TypeVar, cast from autogen_core.components import Image from autogen_core.components.models import RequestUsage @@ -18,23 +18,32 @@ def _is_output_a_tty() -> bool: return sys.stdout.isatty() +T = TypeVar("T", bound=TaskResult | Response) + + async def Console( - stream: AsyncGenerator[AgentMessage | TaskResult, None] | AsyncGenerator[AgentMessage | Response, None], + stream: AsyncGenerator[AgentMessage | T, None], *, no_inline_images: bool = False, -) -> None: - """Consume the stream from :meth:`~autogen_agentchat.base.Team.run_stream` +) -> T: + """ + Consume the stream from :meth:`~autogen_agentchat.base.Team.run_stream` or :meth:`~autogen_agentchat.base.ChatAgent.on_messages_stream` - and print the messages to the console. + print the messages to the console and return the last processed TaskResult or Response. Args: stream (AsyncGenerator[AgentMessage | TaskResult, None] | AsyncGenerator[AgentMessage | Response, None]): Stream to render no_inline_images (bool, optional): If terminal is iTerm2 will render images inline. Use this to disable this behavior. Defaults to False. - """ + Returns: + last_processed: The last processed TaskResult or Response. + """ render_image_iterm = _is_running_in_iterm() and _is_output_a_tty() and not no_inline_images start_time = time.time() total_usage = RequestUsage(prompt_tokens=0, completion_tokens=0) + + last_processed: Optional[T] = None + async for message in stream: if isinstance(message, TaskResult): duration = time.time() - start_time @@ -47,6 +56,9 @@ async def Console( f"Duration: {duration:.2f} seconds\n" ) sys.stdout.write(output) + # mypy ignore + last_processed = message # type: ignore + elif isinstance(message, Response): duration = time.time() - start_time @@ -71,7 +83,12 @@ async def Console( f"Duration: {duration:.2f} seconds\n" ) sys.stdout.write(output) + # mypy ignore + last_processed = message # type: ignore + else: + # Cast required for mypy to be happy + message = cast(AgentMessage, message) # type: ignore output = f"{'-' * 10} {message.source} {'-' * 10}\n{_message_to_str(message, render_image_iterm=render_image_iterm)}\n" if message.models_usage: output += f"[Prompt tokens: {message.models_usage.prompt_tokens}, Completion tokens: {message.models_usage.completion_tokens}]\n" @@ -79,6 +96,11 @@ async def Console( total_usage.prompt_tokens += message.models_usage.prompt_tokens sys.stdout.write(output) + if last_processed is None: + raise ValueError("No TaskResult or Response was processed.") + + return last_processed + # iTerm2 image rendering protocol: https://iterm2.com/documentation-images.html def _image_to_iterm(image: Image) -> str: diff --git a/python/packages/autogen-agentchat/tests/test_group_chat.py b/python/packages/autogen-agentchat/tests/test_group_chat.py index b6c4f4bfdc7b..7df27abcbcd5 100644 --- a/python/packages/autogen-agentchat/tests/test_group_chat.py +++ b/python/packages/autogen-agentchat/tests/test_group_chat.py @@ -24,7 +24,7 @@ ToolCallMessage, ToolCallResultMessage, ) -from autogen_agentchat.task import HandoffTermination, MaxMessageTermination, TextMentionTermination +from autogen_agentchat.task import Console, HandoffTermination, MaxMessageTermination, TextMentionTermination from autogen_agentchat.teams import ( RoundRobinGroupChat, SelectorGroupChat, @@ -315,6 +315,14 @@ async def test_round_robin_group_chat_with_tools(monkeypatch: pytest.MonkeyPatch assert message == result.messages[index] index += 1 + # Test Console. + tool_use_agent._model_context.clear() # pyright: ignore + mock.reset() + index = 0 + await team.reset() + result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'")) + assert result2 == result + @pytest.mark.asyncio async def test_round_robin_group_chat_with_resume_and_reset() -> None: @@ -476,6 +484,14 @@ async def test_selector_group_chat(monkeypatch: pytest.MonkeyPatch) -> None: assert message == result.messages[index] index += 1 + # Test Console. + mock.reset() + agent1._count = 0 # pyright: ignore + index = 0 + await team.reset() + result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'")) + assert result2 == result + @pytest.mark.asyncio async def test_selector_group_chat_two_speakers(monkeypatch: pytest.MonkeyPatch) -> None: @@ -528,6 +544,14 @@ async def test_selector_group_chat_two_speakers(monkeypatch: pytest.MonkeyPatch) assert message == result.messages[index] index += 1 + # Test Console. + mock.reset() + agent1._count = 0 # pyright: ignore + index = 0 + await team.reset() + result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'")) + assert result2 == result + @pytest.mark.asyncio async def test_selector_group_chat_two_speakers_allow_repeated(monkeypatch: pytest.MonkeyPatch) -> None: @@ -595,6 +619,13 @@ async def test_selector_group_chat_two_speakers_allow_repeated(monkeypatch: pyte assert message == result.messages[index] index += 1 + # Test Console. + mock.reset() + index = 0 + await team.reset() + result2 = await Console(team.run_stream(task="Write a program that prints 'Hello, world!'")) + assert result2 == result + @pytest.mark.asyncio async def test_selector_group_chat_custom_selector(monkeypatch: pytest.MonkeyPatch) -> None: @@ -792,6 +823,14 @@ async def test_swarm_handoff_using_tool_calls(monkeypatch: pytest.MonkeyPatch) - assert message == result.messages[index] index += 1 + # Test Console + agent1._model_context.clear() # pyright: ignore + mock.reset() + index = 0 + await team.reset() + result2 = await Console(team.run_stream(task="task")) + assert result2 == result + @pytest.mark.asyncio async def test_swarm_pause_and_resume() -> None: From bd811837518fc403bd7161236234fd2447f22f95 Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 11:15:21 -0800 Subject: [PATCH 04/12] .NET renaming Microsoft.AutoGen.* package (#4286) * renaming package * update folder name to match extension structure * more renaming and adding tags * fix header --------- Co-authored-by: Ryan Sweet --- dotnet/AutoGen.sln | 6 +++--- dotnet/nuget/nuget-package.props | 2 +- .../Hello/HelloAIAgents/HelloAIAgents.csproj | 2 +- .../DevTeam.AgentHost.csproj | 2 +- .../DevTeam.Agents/DevTeam.Agents.csproj | 2 +- .../DevTeam.Backend/DevTeam.Backend.csproj | 2 +- .../Microsoft.AutoGen.Abstractions.csproj | 6 +----- .../Agents/Microsoft.AutoGen.Agents.csproj | 9 ++------- .../AspireHostingExtensions.cs} | 4 ++-- ...icrosoft.AutoGen.Extensions.Aspire.csproj} | 2 +- .../MEAIHostingExtensions.cs} | 4 ++-- .../Microsoft.AutoGen.Extensions.MEAI.csproj} | 2 +- .../Options/AIClientOptions.cs | 0 ...rviceCollectionChatCompletionExtensions.cs | 0 ...t.AutoGen.Extensions.SemanticKernel.csproj | 19 +++++++++---------- 15 files changed, 26 insertions(+), 36 deletions(-) rename dotnet/src/Microsoft.AutoGen/Extensions/{ServiceDefaults/Extensions.cs => Aspire/AspireHostingExtensions.cs} (98%) rename dotnet/src/Microsoft.AutoGen/Extensions/{ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj => Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj} (94%) rename dotnet/src/Microsoft.AutoGen/Extensions/{AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs => MEAI/MEAIHostingExtensions.cs} (94%) rename dotnet/src/Microsoft.AutoGen/Extensions/{AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj => MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj} (94%) rename dotnet/src/Microsoft.AutoGen/Extensions/{AIModelClientHostingExtensions => MEAI}/Options/AIClientOptions.cs (100%) rename dotnet/src/Microsoft.AutoGen/Extensions/{AIModelClientHostingExtensions => MEAI}/ServiceCollectionChatCompletionExtensions.cs (100%) diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln index accf92218ab2..5b26e27165b3 100644 --- a/dotnet/AutoGen.sln +++ b/dotnet/AutoGen.sln @@ -122,15 +122,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAIAgents", "samples\He EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAgent", "samples\Hello\HelloAgent\HelloAgent.csproj", "{8F7560CF-EEBB-4333-A69F-838CA40FD85D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AIModelClientHostingExtensions", "src\Microsoft.AutoGen\Extensions\AIModelClientHostingExtensions\AIModelClientHostingExtensions.csproj", "{97550E87-48C6-4EBF-85E1-413ABAE9DBFD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Extensions.MEAI", "src\Microsoft.AutoGen\Extensions\MEAI\Microsoft.AutoGen.Extensions.MEAI.csproj", "{97550E87-48C6-4EBF-85E1-413ABAE9DBFD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{686480D7-8FEC-4ED3-9C5D-CEBE1057A7ED}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAgentState", "samples\Hello\HelloAgentState\HelloAgentState.csproj", "{64EF61E7-00A6-4E5E-9808-62E10993A0E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.ServiceDefaults", "src\Microsoft.AutoGen\Extensions\ServiceDefaults\Microsoft.AutoGen.ServiceDefaults.csproj", "{65059914-5527-4A00-9308-9FAF23D5E85A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Extensions.Aspire", "src\Microsoft.AutoGen\Extensions\Aspire\Microsoft.AutoGen.Extensions.Aspire.csproj", "{65059914-5527-4A00-9308-9FAF23D5E85A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Agents.Tests", "test\Microsoft.AutoGen.Agents.Tests\Microsoft.AutoGen.Agents.Tests.csproj", "{394FDAF8-74F9-4977-94A5-3371737EB774}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Agents.Tests", "test\Microsoft.AutoGen.Agents.Tests\Microsoft.AutoGen.Agents.Tests.csproj", "{394FDAF8-74F9-4977-94A5-3371737EB774}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/dotnet/nuget/nuget-package.props b/dotnet/nuget/nuget-package.props index 50cbafc73b66..380380794dc9 100644 --- a/dotnet/nuget/nuget-package.props +++ b/dotnet/nuget/nuget-package.props @@ -7,7 +7,7 @@ Microsoft AutoGen A programming framework for agentic AI - AI, Artificial Intelligence, SDK + AI, Artificial Intelligence, Agents, Multiagent, SDK $(AssemblyName) diff --git a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj index e49cfd456abc..c33bfeed5a8d 100644 --- a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj +++ b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj @@ -13,6 +13,6 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj index bf1bed178248..7508ae5af56e 100644 --- a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj +++ b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj @@ -10,7 +10,7 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj index d8034a01b99a..46a20c650fb7 100644 --- a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj +++ b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj @@ -10,7 +10,7 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj index c486471984fa..fced2a905aa2 100644 --- a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj +++ b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj @@ -29,7 +29,7 @@ - + diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj index c680e201301b..219d7960760a 100644 --- a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj +++ b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj @@ -1,13 +1,9 @@ - net8.0 + net8.0 enable enable - AutoGen.Core - https://github.com/microsoft/agnext - Microsoft - AutoGenn Core Library diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj index 68b26f88b9c2..4861182adf56 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj +++ b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj @@ -1,19 +1,14 @@ - net8.0 + net8.0 enable enable - Microsoft.AutoGen.Agents - https://github.com/microsoft/autogen - Microsoft - Micrososft AutoGen Agents SDK - ai-agents;event-driven-agents - + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs similarity index 98% rename from dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs index a4eccacb7fd8..0e6781d740eb 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Extensions.cs +// AspireHostingExtensions.cs using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; @@ -15,7 +15,7 @@ namespace Microsoft.Extensions.Hosting; // Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. // This project should be referenced by each service project in your solution. // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults -public static class Extensions +public static class AspireHostingExtensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) { diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj similarity index 94% rename from dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj rename to dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj index b70161c7e776..cf2446f93349 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj @@ -1,6 +1,6 @@ - net8.0 + net8.0 enable enable true diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs similarity index 94% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs index c3c9c197392d..d39f358f8cbe 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// AIModelClientHostingExtensions.cs +// MEAIHostingExtensions.cs using Microsoft.Extensions.AI; namespace Microsoft.Extensions.Hosting; -public static class AIModelClient +public static class MEAIHostingExtensions { public static IHostApplicationBuilder AddChatCompletionService(this IHostApplicationBuilder builder, string serviceName) { diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj similarity index 94% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj index 970ae5db4b78..f9e9ac0dfab5 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj @@ -1,6 +1,6 @@ - net8.0 + net8.0 enable enable diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/Options/AIClientOptions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Options/AIClientOptions.cs similarity index 100% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/Options/AIClientOptions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Options/AIClientOptions.cs diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/ServiceCollectionChatCompletionExtensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/ServiceCollectionChatCompletionExtensions.cs similarity index 100% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/ServiceCollectionChatCompletionExtensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/ServiceCollectionChatCompletionExtensions.cs diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj index 3c7fe517799b..6ee4530895af 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj @@ -1,22 +1,21 @@ - - - - - - - net8.0 + net8.0 enable enable - - - + + + + + + + + From 072a1c14b7b63eaaca8f89edf409e835d6f9b32f Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 11:50:28 -0800 Subject: [PATCH 05/12] update (#4288) --- .azure/pipelines/build.yaml | 2 +- dotnet/Directory.Build.props | 6 +++++- dotnet/eng/MetaInfo.props | 3 ++- .../samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj | 2 +- .../Abstractions/Microsoft.AutoGen.Abstractions.csproj | 2 ++ .../Agents/Microsoft.AutoGen.Agents.csproj | 3 +++ .../Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj | 3 +++ .../MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj | 3 +++ .../Microsoft.AutoGen.Extensions.SemanticKernel.csproj | 2 ++ 9 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.azure/pipelines/build.yaml b/.azure/pipelines/build.yaml index 3d25dfa920a4..6f21e59b00f3 100644 --- a/.azure/pipelines/build.yaml +++ b/.azure/pipelines/build.yaml @@ -30,7 +30,7 @@ parameters: - name: version_suffix displayName: Version suffix type: string - default: ci.$(Build.BuildNumber) + default: dev.$(Build.BuildNumber) - name: codesign displayName: Enable code signing type: boolean diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props index aa4a0673a0f7..e548a4b7ea83 100644 --- a/dotnet/Directory.Build.props +++ b/dotnet/Directory.Build.props @@ -21,7 +21,6 @@ true true false - embedded true @@ -30,6 +29,11 @@ $(MSBuildThisFileDirectory) + + $(VersionPrefixForAutoGen0_2) + true + + $(NoWarn);CA1829 diff --git a/dotnet/eng/MetaInfo.props b/dotnet/eng/MetaInfo.props index 4f3d216aa08c..db46778a06c2 100644 --- a/dotnet/eng/MetaInfo.props +++ b/dotnet/eng/MetaInfo.props @@ -1,7 +1,8 @@ - 0.2.2 + 0.4.0 + 0.2.2 AutoGen https://microsoft.github.io/autogen-for-net/ https://github.com/microsoft/autogen diff --git a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj index fced2a905aa2..10e05cfb2107 100644 --- a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj +++ b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj @@ -29,7 +29,7 @@ - + diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj index 219d7960760a..d9596f607ccb 100644 --- a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj +++ b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj index 4861182adf56..aa79cf9665ae 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj +++ b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj @@ -6,6 +6,9 @@ enable + + + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj index cf2446f93349..0cab61bc27b6 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj @@ -5,6 +5,9 @@ enable true + + + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj index f9e9ac0dfab5..b8233a8e6c50 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj @@ -4,6 +4,9 @@ enable enable + + + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj index 6ee4530895af..c4ac5536e70c 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj @@ -5,6 +5,8 @@ enable + + From 9a26bd7beb7908d94d7459732a6c94ceedb0f61f Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 17:08:46 -0800 Subject: [PATCH 06/12] .NET update nightly build feed to use AGPublic (#4284) * update nightly build feed * Update README.md --------- Co-authored-by: Ryan Sweet --- dotnet/README.md | 8 +++----- dotnet/website/articles/Installation.md | 6 +----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/dotnet/README.md b/dotnet/README.md index a5705114d72a..c34679389fc0 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -1,12 +1,12 @@ # AutoGen for .NET Thre are two sets of packages here: -Autogen.\* the older packages derived from Autogen 0.2 for .NET - these will gradually be deprecated and ported into the new packages +AutoGen.\* the older packages derived from AutoGen 0.2 for .NET - these will gradually be deprecated and ported into the new packages Microsoft.AutoGen.* the new packages for .NET that use the event-driven model - These APIs are not yet stable and are subject to change. To get started with the new packages, please see the [samples](./samples/) and in particular the [Hello](./samples/Hello) sample. -The remaining content is for the older Autogen.* packages. +You can install both new and old packages from the following feeds: [![dotnet-ci](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml/badge.svg)](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml) [![NuGet version](https://badge.fury.io/nu/AutoGen.Core.svg)](https://badge.fury.io/nu/AutoGen.Core) @@ -14,9 +14,7 @@ The remaining content is for the older Autogen.* packages. > [!NOTE] > Nightly build is available at: > -> - ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/github-grey?style=flat): -> - ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/myget-grey?style=flat): -> - ![Static Badge](https://img.shields.io/badge/internal-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat) : +> - [![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat)](https://dev.azure.com/AGPublish/AGPublic/_artifacts/feed/AutoGen-Nightly) : Firstly, following the [installation guide](./website/articles/Installation.md) to install AutoGen packages. diff --git a/dotnet/website/articles/Installation.md b/dotnet/website/articles/Installation.md index 30b55442d246..b421304b04be 100644 --- a/dotnet/website/articles/Installation.md +++ b/dotnet/website/articles/Installation.md @@ -32,9 +32,7 @@ dotnet add package AUTOGEN_PACKAGES ### Consume nightly build To consume nightly build, you can add one of the following feeds to your `NuGet.config` or global nuget config: -- ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/github-grey?style=flat): https://nuget.pkg.github.com/microsoft/index.json -- ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/myget-grey?style=flat): https://www.myget.org/F/agentchat/api/v3/index.json -- ![Static Badge](https://img.shields.io/badge/internal-blue?style=flat) ![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat) : https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/AutoGen/nuget/v3/index.json +> - [![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat)](https://dev.azure.com/AGPublish/AGPublic/_artifacts/feed/AutoGen-Nightly) : To add a local `NuGet.config`, create a file named `NuGet.config` in the root of your project and add the following content: ```xml @@ -42,8 +40,6 @@ To add a local `NuGet.config`, create a file named `NuGet.config` in the root of - - From 6ffa42ba44e987295aaacd624f0cbb89147ce5bc Mon Sep 17 00:00:00 2001 From: Gerardo Moreno Date: Wed, 20 Nov 2024 18:03:39 -0800 Subject: [PATCH 07/12] Swarm Tutorial (#4146) * Swarm Tutorial * Include 2 swarm example, add svgs * Include latest Swarm changes & Eric changes * Update docs to remove UserProxyAgent * Include latest Console changes --------- Co-authored-by: Eric Zhu --- .../docs/drawio/swarm_customer_support.drawio | 56 ++ .../docs/drawio/swarm_stock_research.drawio | 73 +++ .../agentchat-user-guide/tutorial/swarm.ipynb | 541 +++++++++++++++++- .../tutorial/swarm_customer_support.svg | 3 + .../tutorial/swarm_stock_research.svg | 3 + 5 files changed, 674 insertions(+), 2 deletions(-) create mode 100644 python/packages/autogen-core/docs/drawio/swarm_customer_support.drawio create mode 100644 python/packages/autogen-core/docs/drawio/swarm_stock_research.drawio create mode 100644 python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_customer_support.svg create mode 100644 python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_stock_research.svg diff --git a/python/packages/autogen-core/docs/drawio/swarm_customer_support.drawio b/python/packages/autogen-core/docs/drawio/swarm_customer_support.drawio new file mode 100644 index 000000000000..798b921cd5ef --- /dev/null +++ b/python/packages/autogen-core/docs/drawio/swarm_customer_support.drawio @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/packages/autogen-core/docs/drawio/swarm_stock_research.drawio b/python/packages/autogen-core/docs/drawio/swarm_stock_research.drawio new file mode 100644 index 000000000000..83d699e5decd --- /dev/null +++ b/python/packages/autogen-core/docs/drawio/swarm_stock_research.drawio @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb index f6b93a0abc3f..6ff950b10ef0 100644 --- a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb @@ -4,13 +4,550 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Swarm" + "# Swarm\n", + "\n", + "{py:class}`~autogen_agentchat.teams.Swarm` implements a team in which agents can hand off \n", + "task to other agents based on their capabilities. \n", + "It is a multi-agent design pattern first introduced by OpenAI in \n", + "[an experimental project](https://github.com/openai/swarm).\n", + "The key idea is to let agent delegate tasks to other agents using a special tool call, while\n", + "all agents share the same message context.\n", + "This enables agents to make local decisions about task planning, rather than\n", + "relying on a central orchestrator such as in {py:class}`~autogen_agentchat.teams.SelectorGroupChat`.\n", + "\n", + "```{note}\n", + "{py:class}`~autogen_agentchat.teams.Swarm` is a high-level API. If you need more\n", + "control and customization that is not supported by this API, you can take a look\n", + "at the [Handoff Pattern](../../core-user-guide/design-patterns/handoffs.ipynb)\n", + "in the Core API documentation and implement your own version of the Swarm pattern.\n", + "```\n", + "\n", + "## How Does It Work?\n", + "\n", + "At its core, the {py:class}`~autogen_agentchat.teams.Swarm` team is a group chat\n", + "where agents take turn to generate a response. \n", + "Similar to the {py:class}`~autogen_agentchat.teams.SelectorGroupChat`\n", + "and {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`: participant agents\n", + "all share the same mesasge context.\n", + "\n", + "But different from the other two group chat teams, at each turn,\n", + "**the speaker agent is selected based on the most recent\n", + "{py:class}`~autogen_agentchat.messages.HandoffMessage` message in the context.**\n", + "This naturally requires each agent in the team to be able to generate\n", + "{py:class}`~autogen_agentchat.messages.HandoffMessage` to signal\n", + "which other agents that it hands off to.\n", + "\n", + "For {py:class}`~autogen_agentchat.agents.AssistantAgent`, you can set the\n", + "`handoffs` argument to specify which agents it can hand off to. You can\n", + "use {py:class}`~autogen_agentchat.agents.Handoff` to customize the message\n", + "content and handoff behavior.\n", + "\n", + "The overall process can be summarized as follows:\n", + "\n", + "1. Each agent has the ability to generate {py:class}`~autogen_agentchat.messages.HandoffMessage`\n", + " to signal which other agents it can hand off to. For {py:class}`~autogen_agentchat.agents.AssistantAgent`, this means setting the `handoffs` argument.\n", + "2. When the team starts on a task, the first speaker agents operate on the task and make locallized decision about whether to hand off and to whom.\n", + "3. When an agent generates a {py:class}`~autogen_agentchat.messages.HandoffMessage`, the receiving agent takes over the task with the same message context.\n", + "4. The process continues until a termination condition is met.\n", + "\n", + "In this section, we will show you two examples of how to use the {py:class}`~autogen_agentchat.teams.Swarm` team:\n", + "\n", + "1. A customer support team with human-in-the-loop handoff.\n", + "2. An automonous team for content generation." ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Customer Support Example" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Customer Support](swarm_customer_support.svg)\n", + "\n", + "This system implements a flights refund scenario with two agents:\n", + "\n", + "- **Travel Agent**: Handles general travel and refund coordination.\n", + "- **Flights Refunder**: Specializes in processing flight refunds with the `refund_flight` tool.\n", + "\n", + "Additionally, we let the user interact with the agents, when agents handoff to `\"user\"`.\n", + "\n", + "#### Workflow:\n", + "1. The **Travel Agent** initiates the conversation and evaluates the user's request.\n", + "2. Based on the request:\n", + " - For refund-related tasks, the Travel Agent hands off to the **Flights Refunder**.\n", + " - For information needed from the customer, either agent can hand off to the `\"user\"`.\n", + "3. The **Flights Refunder** processes refunds using the `refund_flight` tool when appropriate.\n", + "4. If an agent hands off to the `\"user\"`, the team execution will stop and wait for the user to input a response.\n", + "5. When the user provides input, it's sent back to the team as a {py:class}`~autogen_agentchat.messages.HandaffMessage`. This message is directed to the agent that originally requested user input.\n", + "6. The process continues until the Travel Agent determines the task is complete and terminates the workflow." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Any, Dict, List\n", + "\n", + "from autogen_agentchat.agents import AssistantAgent\n", + "from autogen_agentchat.messages import HandoffMessage\n", + "from autogen_agentchat.task import Console, HandoffTermination, TextMentionTermination\n", + "from autogen_agentchat.teams import Swarm\n", + "from autogen_ext.models import OpenAIChatCompletionClient" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tools" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def refund_flight(flight_id: str) -> str:\n", + " \"\"\"Refund a flight\"\"\"\n", + " return f\"Flight {flight_id} refunded\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Agents" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "model_client = OpenAIChatCompletionClient(\n", + " model=\"gpt-4o\",\n", + " # api_key=\"YOUR_API_KEY\",\n", + ")\n", + "\n", + "travel_agent = AssistantAgent(\n", + " \"travel_agent\",\n", + " model_client=model_client,\n", + " handoffs=[\"flights_refunder\", \"user\"],\n", + " system_message=\"\"\"You are a travel agent.\n", + " The flights_refunder is in charge of refunding flights.\n", + " If you need information from the user, you must first send your message, then you can handoff to the user.\n", + " Use TERMINATE when the travel planning is complete.\"\"\",\n", + ")\n", + "\n", + "flights_refunder = AssistantAgent(\n", + " \"flights_refunder\",\n", + " model_client=model_client,\n", + " handoffs=[\"travel_agent\", \"user\"],\n", + " tools=[refund_flight],\n", + " system_message=\"\"\"You are an agent specialized in refunding flights.\n", + " You only need flight reference numbers to refund a flight.\n", + " You have the ability to refund a flight using the refund_flight tool.\n", + " If you need information from the user, you must first send your message, then you can handoff to the user.\n", + " When the transaction is complete, handoff to the travel agent to finalize.\"\"\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "termination = HandoffTermination(target=\"user\") | TextMentionTermination(\"TERMINATE\")\n", + "team = Swarm([travel_agent, flights_refunder], termination_condition=termination)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---------- user ----------\n", + "I need to refund my flight.\n", + "---------- travel_agent ----------\n", + "[FunctionCall(id='call_epnozsBbe9i4swPaaBIR4Enl', arguments='{}', name='transfer_to_flights_refunder')]\n", + "[Prompt tokens: 327, Completion tokens: 14]\n", + "---------- travel_agent ----------\n", + "[FunctionExecutionResult(content='Transferred to flights_refunder, adopting the role of flights_refunder immediately.', call_id='call_epnozsBbe9i4swPaaBIR4Enl')]\n", + "---------- travel_agent ----------\n", + "Transferred to flights_refunder, adopting the role of flights_refunder immediately.\n", + "---------- flights_refunder ----------\n", + "I can help you with that. Could you please provide me with your flight reference number so I can process the refund?\n", + "[Prompt tokens: 450, Completion tokens: 25]\n", + "---------- flights_refunder ----------\n", + "[FunctionCall(id='call_giMQVbQ7mXahC5G3eC0wvnCv', arguments='{}', name='transfer_to_user')]\n", + "[Prompt tokens: 483, Completion tokens: 11]\n", + "---------- flights_refunder ----------\n", + "[FunctionExecutionResult(content='Transferred to user, adopting the role of user immediately.', call_id='call_giMQVbQ7mXahC5G3eC0wvnCv')]\n", + "---------- flights_refunder ----------\n", + "Transferred to user, adopting the role of user immediately.\n", + "---------- Summary ----------\n", + "Number of messages: 8\n", + "Finish reason: Handoff to user from flights_refunder detected.\n", + "Total prompt tokens: 1260\n", + "Total completion tokens: 50\n", + "Duration: 1.79 seconds\n", + "---------- user ----------\n", + "Sure, it's 507811\n", + "---------- flights_refunder ----------\n", + "[FunctionCall(id='call_ACcFykJ3fPzanMwy1YGxG4L4', arguments='{\"flight_id\":\"507811\"}', name='refund_flight')]\n", + "[Prompt tokens: 530, Completion tokens: 18]\n", + "---------- flights_refunder ----------\n", + "[FunctionExecutionResult(content='Flight 507811 refunded', call_id='call_ACcFykJ3fPzanMwy1YGxG4L4')]\n", + "---------- flights_refunder ----------\n", + "Your flight with the reference number 507811 has been successfully refunded. If there is anything else you need help with, feel free to ask!\n", + "[Prompt tokens: 488, Completion tokens: 30]\n", + "---------- flights_refunder ----------\n", + "[FunctionCall(id='call_9NjAP8yD1qgwNL4Zfntt4dVb', arguments='{}', name='transfer_to_travel_agent')]\n", + "[Prompt tokens: 605, Completion tokens: 13]\n", + "---------- flights_refunder ----------\n", + "[FunctionExecutionResult(content='Transferred to travel_agent, adopting the role of travel_agent immediately.', call_id='call_9NjAP8yD1qgwNL4Zfntt4dVb')]\n", + "---------- flights_refunder ----------\n", + "Transferred to travel_agent, adopting the role of travel_agent immediately.\n", + "---------- travel_agent ----------\n", + "If you need further assistance with travel planning or any other inquiries, just let me know. Have a wonderful day!\n", + "[Prompt tokens: 495, Completion tokens: 24]\n", + "---------- travel_agent ----------\n", + "TERMINATE\n", + "[Prompt tokens: 525, Completion tokens: 4]\n", + "---------- Summary ----------\n", + "Number of messages: 9\n", + "Finish reason: Text 'TERMINATE' mentioned\n", + "Total prompt tokens: 2643\n", + "Total completion tokens: 89\n", + "Duration: 6.63 seconds\n" + ] + } + ], + "source": [ + "task = \"I need to refund my flight.\"\n", + "\n", + "\n", + "async def run_team_stream() -> None:\n", + " task_result = await Console(team.run_stream(task=task))\n", + " last_message = task_result.messages[-1]\n", + "\n", + " while isinstance(last_message, HandoffMessage) and last_message.target == \"user\":\n", + " user_message = input(\"User: \")\n", + "\n", + " task_result = await Console(\n", + " team.run_stream(task=HandoffMessage(source=\"user\", target=last_message.source, content=user_message))\n", + " )\n", + " last_message = task_result.messages[-1]\n", + "\n", + "\n", + "await run_team_stream()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stock Research Example" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Stock Research](swarm_stock_research.svg)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This system is designed to perform stock research tasks by leveraging four agents:\n", + "\n", + "- **Planner**: The central coordinator that delegates specific tasks to specialized agents based on their expertise. The planner ensures that each agent is utilized efficiently and oversees the overall workflow.\n", + "- **Financial Analyst**: A specialized agent responsible for analyzing financial metrics and stock data using tools such as `get_stock_data`.\n", + "- **News Analyst**: An agent focused on gathering and summarizing recent news articles relevant to the stock, using tools such as `get_news`.\n", + "- **Writer**: An agent tasked with compiling the findings from the stock and news analysis into a cohesive final report.\n", + "\n", + "#### Workflow:\n", + "1. The **Planner** initiates the research process by delegating tasks to the appropriate agents in a step-by-step manner.\n", + "2. Each agent performs its task independently and appends their work to the shared **message thread/history**. Rather than directly returning results to the planner, all agents contribute to and read from this shared message history. When agents generate their work using the LLM, they have access to this shared message history, which provides context and helps track the overall progress of the task.\n", + "3. Once an agent completes its task, it hands off control back to the planner.\n", + "4. The process continues until the planner determines that all necessary tasks have been completed and decides to terminate the workflow." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tools" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "async def get_stock_data(symbol: str) -> Dict[str, Any]:\n", + " \"\"\"Get stock market data for a given symbol\"\"\"\n", + " return {\"price\": 180.25, \"volume\": 1000000, \"pe_ratio\": 65.4, \"market_cap\": \"700B\"}\n", + "\n", + "\n", + "async def get_news(query: str) -> List[Dict[str, str]]:\n", + " \"\"\"Get recent news articles about a company\"\"\"\n", + " return [\n", + " {\n", + " \"title\": \"Tesla Expands Cybertruck Production\",\n", + " \"date\": \"2024-03-20\",\n", + " \"summary\": \"Tesla ramps up Cybertruck manufacturing capacity at Gigafactory Texas, aiming to meet strong demand.\",\n", + " },\n", + " {\n", + " \"title\": \"Tesla FSD Beta Shows Promise\",\n", + " \"date\": \"2024-03-19\",\n", + " \"summary\": \"Latest Full Self-Driving beta demonstrates significant improvements in urban navigation and safety features.\",\n", + " },\n", + " {\n", + " \"title\": \"Model Y Dominates Global EV Sales\",\n", + " \"date\": \"2024-03-18\",\n", + " \"summary\": \"Tesla's Model Y becomes best-selling electric vehicle worldwide, capturing significant market share.\",\n", + " },\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "model_client = OpenAIChatCompletionClient(\n", + " model=\"gpt-4o\",\n", + " # api_key=\"YOUR_API_KEY\",\n", + ")\n", + "\n", + "planner = AssistantAgent(\n", + " \"planner\",\n", + " model_client=model_client,\n", + " handoffs=[\"financial_analyst\", \"news_analyst\", \"writer\"],\n", + " system_message=\"\"\"You are a research planning coordinator.\n", + " Coordinate market research by delegating to specialized agents:\n", + " - Financial Analyst: For stock data analysis\n", + " - News Analyst: For news gathering and analysis\n", + " - Writer: For compiling final report\n", + " Always send your plan first, then handoff to appropriate agent.\n", + " Handoff to a single agent at a time.\n", + " Use TERMINATE when research is complete.\"\"\",\n", + ")\n", + "\n", + "financial_analyst = AssistantAgent(\n", + " \"financial_analyst\",\n", + " model_client=model_client,\n", + " handoffs=[\"planner\"],\n", + " tools=[get_stock_data],\n", + " system_message=\"\"\"You are a financial analyst.\n", + " Analyze stock market data using the get_stock_data tool.\n", + " Provide insights on financial metrics.\n", + " Always handoff back to planner when analysis is complete.\"\"\",\n", + ")\n", + "\n", + "news_analyst = AssistantAgent(\n", + " \"news_analyst\",\n", + " model_client=model_client,\n", + " handoffs=[\"planner\"],\n", + " tools=[get_news],\n", + " system_message=\"\"\"You are a news analyst.\n", + " Gather and analyze relevant news using the get_news tool.\n", + " Summarize key market insights from news.\n", + " Always handoff back to planner when analysis is complete.\"\"\",\n", + ")\n", + "\n", + "writer = AssistantAgent(\n", + " \"writer\",\n", + " model_client=model_client,\n", + " handoffs=[\"planner\"],\n", + " system_message=\"\"\"You are a financial report writer.\n", + " Compile research findings into clear, concise reports.\n", + " Always handoff back to planner when writing is complete.\"\"\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---------- user ----------\n", + "Conduct market research for TSLA stock\n", + "---------- planner ----------\n", + "[FunctionCall(id='call_IXFe9RcGbYGNf0V7B2hvDNJI', arguments='{}', name='transfer_to_financial_analyst')]\n", + "[Prompt tokens: 168, Completion tokens: 149]\n", + "---------- planner ----------\n", + "[FunctionExecutionResult(content='Transferred to financial_analyst, adopting the role of financial_analyst immediately.', call_id='call_IXFe9RcGbYGNf0V7B2hvDNJI')]\n", + "---------- planner ----------\n", + "Transferred to financial_analyst, adopting the role of financial_analyst immediately.\n", + "---------- financial_analyst ----------\n", + "[FunctionCall(id='call_2IYcTAXiufX1SBmnMJOG9HPq', arguments='{\"symbol\":\"TSLA\"}', name='get_stock_data')]\n", + "[Prompt tokens: 136, Completion tokens: 16]\n", + "---------- financial_analyst ----------\n", + "[FunctionExecutionResult(content=\"{'price': 180.25, 'volume': 1000000, 'pe_ratio': 65.4, 'market_cap': '700B'}\", call_id='call_2IYcTAXiufX1SBmnMJOG9HPq')]\n", + "---------- financial_analyst ----------\n", + "Here's the market research for TSLA (Tesla) stock:\n", + "\n", + "- **Current Price**: $180.25\n", + "- **Trading Volume**: 1,000,000 shares\n", + "- **Price to Earnings (P/E) Ratio**: 65.4\n", + "- **Market Capitalization**: $700 Billion\n", + "\n", + "These metrics can help evaluate Tesla's stock performance, value in the market, and overall investment appeal. If you need a specific analysis or additional data, feel free to let me know!\n", + "[Prompt tokens: 162, Completion tokens: 103]\n", + "---------- financial_analyst ----------\n", + "[FunctionCall(id='call_ji8SdlXI1uga2SNenIZMvPOR', arguments='{}', name='transfer_to_planner')]\n", + "[Prompt tokens: 310, Completion tokens: 12]\n", + "---------- financial_analyst ----------\n", + "[FunctionExecutionResult(content='Transferred to planner, adopting the role of planner immediately.', call_id='call_ji8SdlXI1uga2SNenIZMvPOR')]\n", + "---------- financial_analyst ----------\n", + "Transferred to planner, adopting the role of planner immediately.\n", + "---------- planner ----------\n", + "[FunctionCall(id='call_aQUm1B1jzvnWF9aWLwfn2VxS', arguments='{}', name='transfer_to_news_analyst')]\n", + "[Prompt tokens: 346, Completion tokens: 14]\n", + "---------- planner ----------\n", + "[FunctionExecutionResult(content='Transferred to news_analyst, adopting the role of news_analyst immediately.', call_id='call_aQUm1B1jzvnWF9aWLwfn2VxS')]\n", + "---------- planner ----------\n", + "Transferred to news_analyst, adopting the role of news_analyst immediately.\n", + "---------- news_analyst ----------\n", + "[FunctionCall(id='call_n5RmgbQgdyfE7EX5NUsKwApq', arguments='{\"query\":\"Tesla stock performance\"}', name='get_news')]\n", + "[Prompt tokens: 291, Completion tokens: 16]\n", + "---------- news_analyst ----------\n", + "[FunctionExecutionResult(content='[{\\'title\\': \\'Tesla Expands Cybertruck Production\\', \\'date\\': \\'2024-03-20\\', \\'summary\\': \\'Tesla ramps up Cybertruck manufacturing capacity at Gigafactory Texas, aiming to meet strong demand.\\'}, {\\'title\\': \\'Tesla FSD Beta Shows Promise\\', \\'date\\': \\'2024-03-19\\', \\'summary\\': \\'Latest Full Self-Driving beta demonstrates significant improvements in urban navigation and safety features.\\'}, {\\'title\\': \\'Model Y Dominates Global EV Sales\\', \\'date\\': \\'2024-03-18\\', \\'summary\\': \"Tesla\\'s Model Y becomes best-selling electric vehicle worldwide, capturing significant market share.\"}]', call_id='call_n5RmgbQgdyfE7EX5NUsKwApq')]\n", + "---------- news_analyst ----------\n", + "Here are some recent news articles related to TSLA (Tesla) stock that may influence its market performance:\n", + "\n", + "1. **Tesla Expands Cybertruck Production** (March 20, 2024)\n", + " - Tesla has ramped up its Cybertruck manufacturing capacity at the Gigafactory in Texas, aiming to meet the strong demand for this vehicle.\n", + "\n", + "2. **Tesla FSD Beta Shows Promise** (March 19, 2024)\n", + " - The latest Full Self-Driving (FSD) beta update demonstrates notable improvements in urban navigation and safety features, suggesting potential advancements in Tesla's autonomous driving technology.\n", + "\n", + "3. **Model Y Dominates Global EV Sales** (March 18, 2024)\n", + " - Tesla's Model Y has become the best-selling electric vehicle worldwide, capturing a significant share of the market, which could positively impact the company's revenue streams.\n", + "\n", + "If you'd like a more detailed analysis or further information, please let me know!\n", + "[Prompt tokens: 414, Completion tokens: 192]\n", + "---------- news_analyst ----------\n", + "[FunctionCall(id='call_7Ka5f5k2yZ8flfvZWKNXDQjL', arguments='{}', name='transfer_to_planner')]\n", + "[Prompt tokens: 654, Completion tokens: 12]\n", + "---------- news_analyst ----------\n", + "[FunctionExecutionResult(content='Transferred to planner, adopting the role of planner immediately.', call_id='call_7Ka5f5k2yZ8flfvZWKNXDQjL')]\n", + "---------- news_analyst ----------\n", + "Transferred to planner, adopting the role of planner immediately.\n", + "---------- planner ----------\n", + "[FunctionCall(id='call_zl0E18TZWoCPykYqG7jpR2mr', arguments='{}', name='transfer_to_writer')]\n", + "[Prompt tokens: 611, Completion tokens: 11]\n", + "---------- planner ----------\n", + "[FunctionExecutionResult(content='Transferred to writer, adopting the role of writer immediately.', call_id='call_zl0E18TZWoCPykYqG7jpR2mr')]\n", + "---------- planner ----------\n", + "Transferred to writer, adopting the role of writer immediately.\n", + "---------- writer ----------\n", + "### Market Research Report: Tesla (TSLA) Stock\n", + "\n", + "#### Stock Performance Overview\n", + "\n", + "- **Current Price**: $180.25\n", + "- **Trading Volume**: 1,000,000 shares\n", + "- **Price to Earnings (P/E) Ratio**: 65.4\n", + "- **Market Capitalization**: $700 Billion\n", + "\n", + "Tesla's stock is currently valued at $180.25 per share, with a high trading volume reflecting active investor interest. The P/E ratio of 65.4 indicates that the stock might be viewed as overvalued compared to traditional industries, but it is common for tech and innovation-driven companies. The market capitalization of $700 billion underscores Tesla’s significant presence in the automotive and technology markets.\n", + "\n", + "#### Recent News Impacting Tesla (TSLA)\n", + "\n", + "1. **Expansion of Cybertruck Production**: Tesla has increased its Cybertruck production at the Texas Gigafactory, responding to heightened demand. This expansion strategy could drive future revenues and solidify Tesla's innovative image.\n", + "\n", + "2. **Advancements in Full Self-Driving (FSD) Technology**: The latest Tesla FSD beta update highlights promising improvements. Enhanced safety and urban navigation may bolster Tesla's reputation in the autonomous vehicle domain, potentially increasing its market value.\n", + "\n", + "3. **Model Y's Global Sales Leadership**: The Model Y has emerged as the leading global electric vehicle in terms of sales. This achievement not only boosts Tesla's revenue streams but also cements its position as a leader in the EV segment.\n", + "\n", + "### Conclusion\n", + "\n", + "Tesla’s market dynamics show strong innovation and consumer interest, which reflect positively in its stock market valuation and significant news coverage. The company continues to lead in the electric vehicle market and expand its capabilities in autonomous driving, thereby potentially increasing its financial performance and market leadership.\n", + "\n", + "For further analysis or inquiries, feel free to reach out.\n", + "[Prompt tokens: 489, Completion tokens: 371]\n", + "---------- writer ----------\n", + "[FunctionCall(id='call_9buNd5ud2MTRyX50X2EjQJqp', arguments='{}', name='transfer_to_planner')]\n", + "[Prompt tokens: 865, Completion tokens: 12]\n", + "---------- writer ----------\n", + "[FunctionExecutionResult(content='Transferred to planner, adopting the role of planner immediately.', call_id='call_9buNd5ud2MTRyX50X2EjQJqp')]\n", + "---------- writer ----------\n", + "Transferred to planner, adopting the role of planner immediately.\n", + "---------- planner ----------\n", + "TERMINATE\n", + "[Prompt tokens: 1037, Completion tokens: 4]\n", + "---------- Summary ----------\n", + "Number of messages: 27\n", + "Finish reason: Text 'TERMINATE' mentioned\n", + "Total prompt tokens: 5483\n", + "Total completion tokens: 912\n", + "Duration: 15.26 seconds\n" + ] + } + ], + "source": [ + "# Define termination condition\n", + "text_termination = TextMentionTermination(\"TERMINATE\")\n", + "termination = text_termination\n", + "\n", + "research_team = Swarm(\n", + " participants=[planner, financial_analyst, news_analyst, writer], termination_condition=termination\n", + ")\n", + "\n", + "task = \"Conduct market research for TSLA stock\"\n", + "await Console(research_team.run_stream(task=task))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { + "kernelspec": { + "display_name": "autogen", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" } }, "nbformat": 4, diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_customer_support.svg b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_customer_support.svg new file mode 100644 index 000000000000..c2dcde2bba67 --- /dev/null +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_customer_support.svg @@ -0,0 +1,3 @@ + + +
Application/User
Application/User
Team
Team
Travel Agent
Travel Agent
Flights Refunder Agent
Flights Refunder Age...
Handoff Message
Handoff Message
refund_flight
refund_flight
Handoff
Message
Handoff...
\ No newline at end of file diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_stock_research.svg b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_stock_research.svg new file mode 100644 index 000000000000..f75d43269caf --- /dev/null +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm_stock_research.svg @@ -0,0 +1,3 @@ + + +
Planner
Planner
Writer
Writer
News 
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22Writer%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BstrokeColor%3D%239999FF%3BgradientColor%3Ddefault%3BfillColor%3Dnone%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22780%22%20y%3D%22377%22%20width%3D%22120%22%20height%3D%2260%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3EAnalyst
News...
Financial
Analyst
Financial...
Handoff
Handoff
Handoff
Handoff
Handoff
Handoff
get_stock_data
get_stock_data
get_news
get_news
\ No newline at end of file From 773e62f462083ec8893192be0aa76b7e13925576 Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 18:28:51 -0800 Subject: [PATCH 08/12] Update toc.yml (#4291) --- dotnet/website/release_note/toc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet/website/release_note/toc.yml b/dotnet/website/release_note/toc.yml index 6f070c70b861..5a423078ac64 100644 --- a/dotnet/website/release_note/toc.yml +++ b/dotnet/website/release_note/toc.yml @@ -2,7 +2,7 @@ href: 0.2.2.md - name: 0.2.1 -href: 0.2.1.md + href: 0.2.1.md - name: 0.2.0 href: 0.2.0.md @@ -17,4 +17,4 @@ href: 0.2.1.md href: 0.0.16.md - name: 0.0.0 - 0.0.15 - href: update.md \ No newline at end of file + href: update.md From 0d79b4b2e8529d2727a2c18b074da9ffbfeb7b8d Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Wed, 20 Nov 2024 18:51:53 -0800 Subject: [PATCH 09/12] Remove discord link (#4293) --- dotnet/website/articles/getting-start.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dotnet/website/articles/getting-start.md b/dotnet/website/articles/getting-start.md index fe10a597aacd..0d4bf3316364 100644 --- a/dotnet/website/articles/getting-start.md +++ b/dotnet/website/articles/getting-start.md @@ -1,6 +1,5 @@ ### Get start with AutoGen for dotnet [![dotnet-ci](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml/badge.svg)](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml) -[![Discord](https://img.shields.io/discord/1153072414184452236?logo=discord&style=flat)](https://discord.gg/pAbnFJrkgZ) [![NuGet version](https://badge.fury.io/nu/AutoGen.Core.svg)](https://badge.fury.io/nu/AutoGen.Core) Firstly, add `AutoGen` package to your project. From 6e4609a76eb1c0607a1cee2f712c003c20b2f1c8 Mon Sep 17 00:00:00 2001 From: Eric Zhu Date: Thu, 21 Nov 2024 03:25:53 -0500 Subject: [PATCH 10/12] External termination condition (#4294) --- .../src/autogen_agentchat/task/__init__.py | 2 + .../autogen_agentchat/task/_terminations.py | 42 +++++++++++++++++++ .../tests/test_termination_condition.py | 16 +++++++ 3 files changed, 60 insertions(+) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/task/__init__.py b/python/packages/autogen-agentchat/src/autogen_agentchat/task/__init__.py index 2a57b0e9cb62..dd7b6265ad44 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/task/__init__.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/task/__init__.py @@ -1,5 +1,6 @@ from ._console import Console from ._terminations import ( + ExternalTermination, HandoffTermination, MaxMessageTermination, StopMessageTermination, @@ -15,5 +16,6 @@ "TokenUsageTermination", "HandoffTermination", "TimeoutTermination", + "ExternalTermination", "Console", ] diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/task/_terminations.py b/python/packages/autogen-agentchat/src/autogen_agentchat/task/_terminations.py index 16d44b9840d3..31b8d9d3eec0 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/task/_terminations.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/task/_terminations.py @@ -208,3 +208,45 @@ async def __call__(self, messages: Sequence[AgentMessage]) -> StopMessage | None async def reset(self) -> None: self._start_time = time.monotonic() self._terminated = False + + +class ExternalTermination(TerminationCondition): + """A termination condition that is externally controlled + by calling the :meth:`set` method. + + Example: + + .. code-block:: python + + termination = ExternalTermination() + + # Run the team in an asyncio task. + ... + + # Set the termination condition externally + termination.set() + + """ + + def __init__(self) -> None: + self._terminated = False + self._setted = False + + @property + def terminated(self) -> bool: + return self._terminated + + def set(self) -> None: + self._setted = True + + async def __call__(self, messages: Sequence[AgentMessage]) -> StopMessage | None: + if self._terminated: + raise TerminatedException("Termination condition has already been reached") + if self._setted: + self._terminated = True + return StopMessage(content="External termination requested", source="ExternalTermination") + return None + + async def reset(self) -> None: + self._terminated = False + self._setted = False diff --git a/python/packages/autogen-agentchat/tests/test_termination_condition.py b/python/packages/autogen-agentchat/tests/test_termination_condition.py index a56d8df356cc..c09e0e1c14ac 100644 --- a/python/packages/autogen-agentchat/tests/test_termination_condition.py +++ b/python/packages/autogen-agentchat/tests/test_termination_condition.py @@ -3,6 +3,7 @@ import pytest from autogen_agentchat.messages import HandoffMessage, StopMessage, TextMessage from autogen_agentchat.task import ( + ExternalTermination, HandoffTermination, MaxMessageTermination, StopMessageTermination, @@ -226,3 +227,18 @@ async def test_timeout_termination() -> None: assert await termination([TextMessage(content="Hello", source="user")]) is None await asyncio.sleep(0.2) assert await termination([TextMessage(content="World", source="user")]) is not None + + +@pytest.mark.asyncio +async def test_external_termination() -> None: + termination = ExternalTermination() + + assert await termination([]) is None + assert not termination.terminated + + termination.set() + assert await termination([]) is not None + assert termination.terminated + + await termination.reset() + assert await termination([]) is None From 415d049822f6beb3cb473959267a80f8ddf8b54e Mon Sep 17 00:00:00 2001 From: Xiaoyun Zhang Date: Thu, 21 Nov 2024 09:53:23 -0800 Subject: [PATCH 11/12] .NET add document on packaging && disable uploading artifacts folder to pipeline by default (#4299) * add package readme * Update PACKAGING.md --- .azure/pipelines/build.yaml | 12 +++++--- .azure/pipelines/templates/build.yaml | 12 ++++++-- dotnet/PACKAGING.md | 41 +++++++++++++++++++++++++++ dotnet/nuget/README.md | 13 +++++++++ 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 dotnet/PACKAGING.md create mode 100644 dotnet/nuget/README.md diff --git a/.azure/pipelines/build.yaml b/.azure/pipelines/build.yaml index 6f21e59b00f3..7ce3f0c1efa9 100644 --- a/.azure/pipelines/build.yaml +++ b/.azure/pipelines/build.yaml @@ -3,8 +3,8 @@ trigger: include: - main paths: - exclude: - - samples + include: + - dotnet schedules: - cron: "0 0 * * *" @@ -12,7 +12,6 @@ schedules: branches: include: - main - - 3.x always: true parameters: @@ -46,6 +45,10 @@ parameters: - name: publish_nightly displayName: Publish to autogen-nightly type: boolean + default: true + - name: publish_artifacts + displayName: Publish artifacts + type: boolean default: false - name: runCodeQL3000 default: false @@ -87,4 +90,5 @@ extends: skip_test: ${{ parameters.skip_test }} publish_nightly: ${{ parameters.publish_nightly }} publish_nuget: ${{ parameters.publish_nuget }} - runCodeQL3000: ${{ parameters.runCodeQL3000 }} \ No newline at end of file + runCodeQL3000: ${{ parameters.runCodeQL3000 }} + publish_artifacts: ${{ parameters.publish_artifacts }} \ No newline at end of file diff --git a/.azure/pipelines/templates/build.yaml b/.azure/pipelines/templates/build.yaml index 7e3d82f4d678..0b7dbe990c38 100644 --- a/.azure/pipelines/templates/build.yaml +++ b/.azure/pipelines/templates/build.yaml @@ -30,6 +30,10 @@ parameters: displayName: Publish to nuget.org type: boolean default: false + - name: publish_artifacts + displayName: Publish artifacts + type: boolean + default: false - name: runCodeQL3000 default: false displayName: Run CodeQL3000 tasks @@ -49,9 +53,11 @@ jobs: ${{ if ne(variables['System.TeamProject'], 'GitHub - PR Builds') }}: templateContext: outputs: - - output: pipelineArtifact - targetPath: '$(build.sourcesdirectory)/dotnet/artifacts' - artifactName: artifacts folder + # Publish artifacts if enabled + - ${{ if eq(parameters.publish_artifacts, true) }}: # TODO add eq(parameters.codesign, true) + - output: pipelineArtifact + targetPath: '$(build.sourcesdirectory)/dotnet/artifacts' + artifactName: artifacts folder # Publish packages to nightly - ${{ if eq(parameters.publish_nightly, true) }}: # TODO add eq(parameters.codesign, true) - output: nuget diff --git a/dotnet/PACKAGING.md b/dotnet/PACKAGING.md new file mode 100644 index 000000000000..af03850f7cea --- /dev/null +++ b/dotnet/PACKAGING.md @@ -0,0 +1,41 @@ +# Packaging AutoGen.NET + +This document describes the steps to pack the `AutoGen.NET` project. + +## Prerequisites + +- .NET SDK + +## Create Package + +1. **Restore and Build the Project** +```bash +dotnet restore +dotnet build --configuration Release --no-restore +``` + + +2. **Create the NuGet Package** +```bash +dotnet pack --configuration Release --no-build +``` + +This will generate both the `.nupkg` file and the `.snupkg` file in the `./artifacts/package/release` directory. + +For more details, refer to the [official .NET documentation](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack). + +## Add new project to package list. +By default, when you add a new project to `AutoGen.sln`, it will not be included in the package list. To include the new project in the package, you need to add the following line to the new project's `.csproj` file + +e.g. + +```xml + +``` + +The `nuget-packages.props` enables `IsPackable` to `true` for the project, it also sets nenecessary metadata for the package. + +For more details, refer to the [NuGet folder](./nuget/README.md). + +## Package versioning +The version of the package is defined by `VersionPrefix` and `VersionPrefixForAutoGen0_2` in [MetaInfo.props](./eng/MetaInfo.props). If the name of your project starts with `AutoGen.`, the version will be set to `VersionPrefixForAutoGen0_2`, otherwise it will be set to `VersionPrefix`. diff --git a/dotnet/nuget/README.md b/dotnet/nuget/README.md new file mode 100644 index 000000000000..c95a97624788 --- /dev/null +++ b/dotnet/nuget/README.md @@ -0,0 +1,13 @@ +# NuGet Directory + +This directory contains resources and metadata for packaging the AutoGen.NET SDK as a NuGet package. + +## Files + +- **icon.png**: The icon used for the NuGet package. +- **NUGET.md**: The readme file displayed on the NuGet package page. +- **NUGET-PACKAGE.PROPS**: The MSBuild properties file that defines the packaging settings for the NuGet package. + +## Purpose + +The files in this directory are used to configure and build the NuGet package for the AutoGen.NET SDK, ensuring that it includes necessary metadata, documentation, and resources. \ No newline at end of file From b65269b8f81296d94f67011a49d8012e718ea749 Mon Sep 17 00:00:00 2001 From: Diego Colombo Date: Thu, 21 Nov 2024 19:03:30 +0000 Subject: [PATCH 12/12] create solution for the dev team sample (#4086) Co-authored-by: Ryan Sweet --- dotnet/samples/dev-team/dev team.sln | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 dotnet/samples/dev-team/dev team.sln diff --git a/dotnet/samples/dev-team/dev team.sln b/dotnet/samples/dev-team/dev team.sln new file mode 100644 index 000000000000..f8a7aeacd924 --- /dev/null +++ b/dotnet/samples/dev-team/dev team.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AgentHost", "DevTeam.AgentHost\DevTeam.AgentHost.csproj", "{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Backend", "DevTeam.Backend\DevTeam.Backend.csproj", "{2D4BAD10-85F3-4E4B-B759-13449A212A96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Agents", "DevTeam.Agents\DevTeam.Agents.csproj", "{A51CE540-72B0-4271-B63D-A30CAB61C227}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AppHost", "DevTeam.AppHost\DevTeam.AppHost.csproj", "{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Shared", "DevTeam.Shared\DevTeam.Shared.csproj", "{557701A5-35D8-4CE3-BA75-D5412B4227F5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Release|Any CPU.Build.0 = Release|Any CPU + {2D4BAD10-85F3-4E4B-B759-13449A212A96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D4BAD10-85F3-4E4B-B759-13449A212A96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D4BAD10-85F3-4E4B-B759-13449A212A96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D4BAD10-85F3-4E4B-B759-13449A212A96}.Release|Any CPU.Build.0 = Release|Any CPU + {A51CE540-72B0-4271-B63D-A30CAB61C227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A51CE540-72B0-4271-B63D-A30CAB61C227}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A51CE540-72B0-4271-B63D-A30CAB61C227}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A51CE540-72B0-4271-B63D-A30CAB61C227}.Release|Any CPU.Build.0 = Release|Any CPU + {2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Release|Any CPU.Build.0 = Release|Any CPU + {557701A5-35D8-4CE3-BA75-D5412B4227F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {557701A5-35D8-4CE3-BA75-D5412B4227F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {557701A5-35D8-4CE3-BA75-D5412B4227F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {557701A5-35D8-4CE3-BA75-D5412B4227F5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE04DB59-B8CD-4305-875B-E71442345CCF} + EndGlobalSection +EndGlobal