Skip to content

Commit

Permalink
Merge branch 'main' into declarative_agentchat_agents_vd
Browse files Browse the repository at this point in the history
  • Loading branch information
victordibia authored Jan 17, 2025
2 parents 4db3d58 + 8bd65c6 commit 0f885ba
Show file tree
Hide file tree
Showing 28 changed files with 1,115 additions and 36 deletions.
59 changes: 41 additions & 18 deletions .azure/pipelines/templates/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,20 @@ jobs:
inputs:
useGlobalJson: true
workingDirectory: $(Build.SourcesDirectory)/dotnet
- task: PowerShell@2
displayName: 'Install uv'
inputs:
targetType: 'inline'
script: |
irm https://astral.sh/uv/install.ps1 | iex
$env:Path = "C:\Users\cloudtest\.local\bin;$env:Path"
uv --version
- task: Bash@3
displayName: Install .NET Aspire workload
inputs:
targetType: 'inline'
script: |
dotnet nuget locals all --clear
dotnet nuget locals all --clear
dotnet workload install aspire
- ${{ if eq(variables.runCodeQL3000, 'true') }}:
- task: CodeQL3000Init@0
Expand All @@ -106,6 +114,7 @@ jobs:
arguments: '$(build_flags) /bl:${{parameters.build_configuration}}-Build.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)'
workingDirectory: $(Build.SourcesDirectory)/dotnet
env:
PATH: "C:\\Users\\cloudtest\\.local\\bin;$(PATH)"
${{ if and(eq(parameters.include_suffix, true), eq(parameters.publish_nuget, false)) }}:
VersionSuffix: ${{parameters.version_suffix}}
OfficialBuild: $(official_build)
Expand All @@ -125,16 +134,23 @@ jobs:
inputs:
SourceFolder: '$(build.sourcesdirectory)'
Contents: |
src/**/bin/${{parameters.build_configuration}}/**/AutoGen*.dll
src/**/bin/${{parameters.build_configuration}}/**/Microsoft.AutoGen.*.dll
**/AutoGen*.dll
**/Microsoft.AutoGen.*.dll
TargetFolder: '$(build.artifactstagingdirectory)\codesign'
CleanTargetFolder: true
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
displayName: 'Codesign: ESRP CodeSigning'
inputs:
ConnectedServiceName: 'CodeSign Service (NuGet)'
ConnectedServiceName: 'AI Frontiers ESRP'
AppRegistrationClientId: 'c1e7a5c0-ee6b-4cec-9e11-4dc3f4670042'
AppRegistrationTenantId: '975f013f-7f24-47e8-a7d3-abc4752bf346'
#EsrpClientId: '7129dd35-ad94-49a9-98c7-eb4cf3cd36a9'
#UseMSIAuthentication: true
AuthAKVName: 'aif-autogen-esrp-kv'
AuthCertName: 'AIF-PME-InfrastructureAuth'
AuthSignCertName: 'AutoGenPublishESRPPKI' # this variable is only needed for codesign
FolderPath: '$(build.artifactstagingdirectory)\codesign'
Pattern: '*'
Pattern: '*.dll'
signConfigType: inlineSignParams
inlineOperation: |
[
Expand Down Expand Up @@ -163,15 +179,15 @@ jobs:
"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"
"toolName": "sign",
"toolVersion": "1.0"
},
{
"keyCode": "CP-230012",
"operationSetCode": "SigntoolVerify",
"parameters": [ ],
"toolName": "sign",
"toolVersion": "1.0"
}
]
SessionTimeout: 180
Expand Down Expand Up @@ -200,10 +216,17 @@ jobs:
inputs:
packageType: runtime
version: $(codesign_runtime)
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
displayName: 'Codesign: ESRP CodeSigning (nuget)'
inputs:
ConnectedServiceName: 'CodeSign Service (NuGet)'
ConnectedServiceName: 'AI Frontiers ESRP'
AppRegistrationClientId: 'c1e7a5c0-ee6b-4cec-9e11-4dc3f4670042'
AppRegistrationTenantId: '975f013f-7f24-47e8-a7d3-abc4752bf346'
EsrpClientId: '7129dd35-ad94-49a9-98c7-eb4cf3cd36a9'
UseMSIAuthentication: true
AuthAKVName: 'aif-autogen-esrp-kv'
#AuthCertName: 'AutoGenPublishESRPPKI'
AuthSignCertName: 'AutoGenPublishESRPPKI' # this variable is only needed for codesign
FolderPath: '$(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}'
Pattern: '*.nupkg'
signConfigType: inlineSignParams
Expand All @@ -225,4 +248,4 @@ jobs:
}
]
SessionTimeout: 180
VerboseLogin: true
VerboseLogin: true
30 changes: 30 additions & 0 deletions docs/dotnet/user-guide/core-user-guide/defining-message-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Defining Message Types

Messages are currently required to be Protocol Buffers. To define them, it is necessary to include the Protocol Buffers compiler, through the `Grpc.Tools` package. In your `.csproj` file, add/edit:

```xml
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
```

Then create an include a `.proto` file in the project:

```xml
<ItemGroup>
<Protobuf Include="messages.proto" GrpcServices="Client;Server" Link="messages.proto" />
</ItemGroup>
```

Then define your messages as specified in the [Protocol Buffers Language Guide](https://protobuf.dev/programming-guides/proto3/)

```proto
syntax = "proto3";
package HelloAgents;
option csharp_namespace = "AgentsProtocol";
message TextMessage {
string Source = 1;
string Content = 2;
}
```
46 changes: 46 additions & 0 deletions docs/dotnet/user-guide/core-user-guide/differences-python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Differences from Python

## Agents Self-Interact

When an agent sends a message of a type to which it also listens:

```csharp
[TopicSubscription("default")]
public class MyAgent(
IAgentWorker worker,
[FromKeyedServices("EventTypes")] EventTypes typeRegistry
) :
Agent(worker, typeRegistry),
IHandle<Message>
{
async Task SomeInternalFunctionAsync()
{
Message m;

// ...
await this.PublishMessageAsync(m);
}

public async Task Handle(Message message)
{
// will receive messages sent by SomeInternalFunctionAsync()
}
}
```

Tracked by [#4998](https://github.com/microsoft/autogen/issues/4998)

## 'Local' Runtime is Multithreaded

Unlike the `single_threaded_runtime`, the InProcess (`local: true`) runtime for .NET is multi-threaded, so messages will process in arbitrary order across agents. This means that an agent may process messages sent after the termination request has been made unless checking for termination using the `IHostApplicationLifecycle` service.

## No equivalent to 'stop_when_idle()'

Agents need to request termination explicitly, as there is no meaningful 'idle' state.

## All message types need to be Protocol Buffers

See (linkto: defining-message-types.md) for instructions on defining messages

Tracked by [#4695](https://github.com/microsoft/autogen/issues/4695)
143 changes: 143 additions & 0 deletions docs/dotnet/user-guide/core-user-guide/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Quick Start

Before diving into the core APIs, let’s start with a simple example of two agents that count down from 10 to 1.

We first define the agent classes and their respective procedures for handling messages. We create two agent classes: `Modifier` and `Checker`. The `Modifier` agent modifies a number that is given and the `Check` agent checks the value against a condition. We also define a pair of
messages in a .proto file which will be generated into the message types that will be passed
between the agents.

```proto
syntax = "proto3";
package HelloAgents;
option csharp_namespace = "Microsoft.Autogen.Samples.CountAgent.Protocol";
message CountMessage {
int32 Content = 1;
}
message CountUpdate {
int32 NewCount = 1;
}
```

We create two messages to ensure we have tick-tock behaviour between the agents; if we used a single type, then both agents would receive the other agents' message as well as self-sent messages. (Note: this is a behaviour difference from Python; Issue#4998)

In the project file, we add

```xml
<ItemGroup>
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<Protobuf Include="messages.proto" GrpcServices="Client;Server" Link="messages.proto" />
</ItemGroup>
```

This will ensure the message classes are available for our agents to send/receive.

Now we will define the agents:

```csharp
[TopicSubscription("default")]
public class Modifier(
IAgentWorker worker,
[FromKeyedServices("EventTypes")] EventTypes typeRegistry,
ModifyF modifyFunc
) :
Agent(worker, typeRegistry),
IHandle<CountMessage>
{
public async Task Handle(CountMessage item)
{
// handling code
}
}
```

The `TopicSubscription` attribute defines the set of topics the agents will listen to. Topics (see here) are useful for separaating different logical chains of agent communications.

The first two parameters to the constructor, `IAgentWorker` and `EventTypes` are automatically made available through dependency injection to the workers. (We do not allow direct construction of workers in Autogen.Core: see here for FAQ), and need to be passed on to the base class.

Other parameters are also made available through dependency injection (see here).

Agents register for messages by implementing the `IHandle<MessageType>` interface:

```csharp
public async Task Handle(CountMessage item)
{
int newValue = modifyFunc(item.Content);
Console.WriteLine($"{SEPARATOR_LINE}\nModifier:\nModified {item.Content} to {newValue}");

CountUpdate updateMessage = new CountUpdate { NewCount = newValue };

await this.PublishMessageAsync(updateMessage);
}
```

The `Modifier` agent receives a `CountMessage` indicating the current count, modifies it using the injected `ModifyF modifyFunc`, and publishes the `CountUpdate` message.

The `Checker` agent is defines similarly:

```csharp
[TopicSubscription("default")]
public class Checker(
IAgentWorker worker,
[FromKeyedServices("EventTypes")] EventTypes typeRegistry,
IHostApplicationLifetime hostApplicationLifetime,
TerminationF runUntilFunc
) :
Agent(worker, typeRegistry),
IHandle<CountUpdate>
{
public Task Handle(CountUpdate item)
{
if (!runUntilFunc(item.NewCount))
{
Console.WriteLine($"{SEPARATOR_LINE}\nChecker:\n{item.NewCount} passed the check, continue.");
await this.PublishMessageAsync(new CountMessage { Content = item.NewCount });
}
else
{
Console.WriteLine($"{SEPARATOR_LINE}\nChecker:\n{item.NewCount} failed the check, stopping.");
hostApplicationLifetime.StopApplication();
}
}
}
```

The `Checker` continues the count when `runUntilFunc` has not triggered by publishing a new `CountMessage` with the updated count; if termination is desired, it will request it by calling `hostApplicationLifetime.StopApplication()`.

You might have already noticed, the agents’ logic, whether it is using model or code executor, is completely decoupled from how messages are delivered. This is the core idea: the framework provides a communication infrastructure, and the agents are responsible for their own logic. We call the communication infrastructure an Agent Runtime.

Agent runtime is a key concept of this framework. Besides delivering messages, it also manages agents’ lifecycle. So the creation of agents are handled by the runtime.

The following code shows how to register and run the agents using the local (InProcess) runtime:

```csharp
// Define the counting logic
using ModifyF = System.Func<int, int>;
using TerminationF = System.Func<int, bool>;

ModifyF modifyFunc = (int x) => x - 1;
TerminationF runUntilFunc = (int x) =>
{
return x <= 1;
};

// Register the services
WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(modifyFunc);
builder.Services.AddSingleton(runUntilFunc);

// Send the initial count to the agents app, running on the `local` runtime, and pass through the registered services via the application `builder`
var app = await AgentsApp.PublishMessageAsync("default", new CountMessage
{
Content = 10
}, local: true, builder: builder).ConfigureAwait(false);

// Run until application shutdown
await app.WaitForShutdownAsync();
```
33 changes: 33 additions & 0 deletions docs/dotnet/user-guide/core-user-guide/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Installation

## Add via `<ProjectReference>`

```
<ProjectReference Include="<path>/<to>/Contracts/Microsoft.AutoGen.Contracts.csproj" />
<ProjectReference Include="<path>/<to>/Core/Microsoft.AutoGen.Core.csproj" />
```

<!-- (TODO: Move to bottom) -->

## These will only work after we release the package:

## Install via `.NET cli`

```
> dotnet add package Microsoft.AutoGen.Contracts --version 0.4.0
> dotnet add package Microsoft.AutoGen.Core --version 0.4.0
```

## Install via `Package Manager`

```
PM> NuGet\Install-Package Microsoft.AutoGen.Contracts -Version 0.4.0
PM> NuGet\Install-Package Microsoft.AutoGen.Core -Version 0.4.0
```

## Add via `<PackageReference>`

```
<PackageReference Include="Microsoft.AutoGen.Contracts" Version="0.2.1" />
<PackageReference Include="Microsoft.AutoGen.Core" Version="0.2.1" />
```
Loading

0 comments on commit 0f885ba

Please sign in to comment.