Skip to content

Commit d5a5fe3

Browse files
2 parents 50dea76 + 288a9cb commit d5a5fe3

32 files changed

+508
-93
lines changed

.github/workflows/checks.yml

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ jobs:
190190
run: |
191191
source ${{ github.workspace }}/python/.venv/bin/activate
192192
poe gen-proto
193+
poe gen-test-proto
193194
working-directory: ./python
194195
- name: Check if there are uncommited changes
195196
id: changes

CONTRIBUTING.md

+55-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,62 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
2424
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
2525
contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
2626

27-
## Roadmaps
27+
## Running CI checks locally
2828

29-
To see what we are working on and what we plan to work on, please check our
30-
[Roadmap Issues](https://aka.ms/autogen-roadmap).
29+
It is important to use `uv` when running CI checks locally as it ensures that the correct dependencies and versions are used.
30+
31+
Please follow the instructions [here](./python/README.md#setup) to get set up.
32+
33+
For common tasks that are helpful during development and run in CI, see [here](./python/README.md#common-tasks).
34+
35+
## Roadmap
36+
37+
We use GitHub issues and milestones to track our roadmap. You can view the upcoming milestones [here]([Roadmap Issues](https://aka.ms/autogen-roadmap).
38+
39+
## Versioning
40+
41+
The set of `autogen-*` packages are generally all versioned together. When a change is made to one package, all packages are updated to the same version. This is to ensure that all packages are in sync with each other.
42+
43+
We will update verion numbers according to the following rules:
44+
45+
- Increase minor version (0.X.0) upon breaking changes
46+
- Increase patch version (0.0.X) upon new features or bug fixes
47+
48+
## Release process
49+
50+
1. Create a PR that updates the version numbers across the codebase ([example](https://github.com/microsoft/autogen/pull/4359))
51+
2. The docs CI will fail for the PR, but this is expected and will be resolved in the next step
52+
2. After merging the PR, create and push a tag that corresponds to the new verion. For example, for `0.4.0.dev7`:
53+
- `git tag 0.4.0.dev7 && git push origin 0.4.0.dev7`
54+
3. Restart the docs CI by finding the failed [job corresponding to the `push` event](https://github.com/microsoft/autogen/actions/workflows/docs.yml) and restarting all jobs
55+
4. Run [this](https://github.com/microsoft/autogen/actions/workflows/single-python-package.yml) workflow for each of the packages that need to be released and get an approval for the release for it to run
56+
57+
## Triage process
58+
59+
To help ensure the health of the project and community the AutoGen committers have a weekly triage process to ensure that all issues and pull requests are reviewed and addressed in a timely manner. The following documents the responsibilites while on triage duty:
60+
61+
- Issues
62+
- Review all new issues - these will be tagged with [`needs-triage`](https://github.com/microsoft/autogen/issues?q=is%3Aissue%20state%3Aopen%20label%3Aneeds-triage).
63+
- Apply appropriate labels:
64+
- One of `proj-*` labels based on the project the issue is related to
65+
- `documentation`: related to documentation
66+
- `x-lang`: related to cross language functionality
67+
- `dotnet`: related to .NET
68+
- Add the issue to a relevant milestone if necessary
69+
- If you can resolve the issue or reply to the OP please do.
70+
- If you cannot resolve the issue, assign it to the appropriate person.
71+
- If awaiting a reply add the tag `awaiting-op-response` (this will be auto removed when the OP replies).
72+
- Bonus: there is a backlog of old issues that need to be reviewed - if you have time, review these as well and close or refresh as many as you can.
73+
- PRs
74+
- The UX on GH flags all recently updated PRs. Draft PRs can be ignored, otherwise review all recently updated PRs.
75+
- If a PR is ready for review and you can provide one please go ahead. If you cant, please assign someone. You can quickly spin up a codespace with the PR to test it out.
76+
- If a PR is needing a reply from the op, please tag it `awaiting-op-response`.
77+
- If a PR is approved and passes CI, its ready to merge, please do so.
78+
- If it looks like there is a possibly transient CI failure, re-run failed jobs.
79+
- Discussions
80+
- Look for recently updated discussions and reply as needed or find someone on the team to reply.
81+
- Security
82+
- Look through any securty alerts and file issues or dismiss as needed.
3183

3284
## Becoming a Reviewer
3385

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<div align="center">
44
<img src="https://microsoft.github.io/autogen/0.2/img/ag.svg" alt="AutoGen Logo" width="100">
55

6-
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/cloudposse.svg?style=social&label=Follow%20%40pyautogen)](https://twitter.com/pyautogen)
6+
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/cloudposse.svg?style=social&label=Follow%20%40pyautogen)](https://twitter.com/pyautogen) [![GitHub Discussions](https://img.shields.io/badge/Discussions-Q%26A-green?logo=github)](https://github.com/microsoft/autogen/discussions) [![0.2 Docs](https://img.shields.io/badge/Docs-0.2-blue)](https://microsoft.github.io/autogen/0.2/) [![0.4 Docs](https://img.shields.io/badge/Docs-0.4-blue)](https://microsoft.github.io/autogen/dev/)
7+
[![PyPi autogen-core](https://img.shields.io/badge/PyPi-autogen--core-blue?logo=pypi)](https://pypi.org/project/autogen-core/0.4.0.dev7/) [![PyPi autogen-agentchat](https://img.shields.io/badge/PyPi-autogen--agentchat-blue?logo=pypi)](https://pypi.org/project/autogen-agentchat/0.4.0.dev7/) [![PyPi autogen-ext](https://img.shields.io/badge/PyPi-autogen--ext-blue?logo=pypi)](https://pypi.org/project/autogen-ext/0.4.0.dev7/)
8+
79

810
</div>
911

@@ -13,6 +15,7 @@
1315
> - (11/14/24) ⚠️ In response to a number of asks to clarify and distinguish between official AutoGen and its forks that created confusion, we issued a [clarification statement](https://github.com/microsoft/autogen/discussions/4217).
1416
> - (10/13/24) Interested in the standard AutoGen as a prior user? Find it at the actively-maintained *AutoGen* [0.2 branch](https://github.com/microsoft/autogen/tree/0.2) and `autogen-agentchat~=0.2` PyPi package.
1517
> - (10/02/24) [AutoGen 0.4](https://microsoft.github.io/autogen/dev) is a from-the-ground-up rewrite of AutoGen. Learn more about the history, goals and future at [this blog post](https://microsoft.github.io/autogen/blog). We’re excited to work with the community to gather feedback, refine, and improve the project before we officially release 0.4. This is a big change, so AutoGen 0.2 is still available, maintained, and developed in the [0.2 branch](https://github.com/microsoft/autogen/tree/0.2).
18+
> - *[Join us for Community Office Hours](https://github.com/microsoft/autogen/discussions/4059)* We will host a weekly open discussion to answer questions, talk about Roadmap, etc.
1619
1720
AutoGen is an open-source framework for building AI agent systems.
1821
It simplifies the creation of event-driven, distributed, scalable, and resilient agentic applications.

docs/design/04 - Agent and Topic ID Specs.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ This document describes the structure, constraints, and behavior of Agent IDs an
3434

3535
- Type: `string`
3636
- Description: Topic type is usually defined by application code to mark the type of messages the topic is for.
37-
- Constraints: UTF8 and only contain alphanumeric letters (a-z) and (0-9), or underscores (\_). A valid identifier cannot start with a number, or contain any spaces.
37+
- Constraints: UTF8 and only contain alphanumeric letters (a-z) and (0-9), ':', '=', or underscores (\_). A valid identifier cannot start with a number, or contain any spaces.
3838
- Examples:
3939
- `GitHub_Issues`
4040

docs/design/readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Docs
2+
3+
You can find the project documentation [here](https://microsoft.github.io/autogen/dev/).

dotnet/src/Microsoft.AutoGen/Agents/AgentBase.cs

+28-15
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,40 @@ namespace Microsoft.AutoGen.Agents;
1515
public abstract class AgentBase : IAgentBase, IHandle, IHandle<CloudEvent>
1616
{
1717
public static readonly ActivitySource s_source = new("AutoGen.Agent");
18-
public AgentId AgentId => _context.AgentId;
18+
public AgentId AgentId => _runtime.AgentId;
1919
private readonly object _lock = new();
2020
private readonly Dictionary<string, TaskCompletionSource<RpcResponse>> _pendingRequests = [];
2121

2222
private readonly Channel<object> _mailbox = Channel.CreateUnbounded<object>();
23-
private readonly IAgentRuntime _context;
23+
private readonly IAgentRuntime _runtime;
2424
public string Route { get; set; } = "base";
2525

2626
protected internal ILogger<AgentBase> _logger;
27-
public IAgentRuntime Context => _context;
27+
public IAgentRuntime Context => _runtime;
2828
protected readonly EventTypes EventTypes;
2929

3030
protected AgentBase(
31-
IAgentRuntime context,
31+
IAgentRuntime runtime,
3232
EventTypes eventTypes,
3333
ILogger<AgentBase>? logger = null)
3434
{
35-
_context = context;
36-
context.AgentInstance = this;
35+
_runtime = runtime;
36+
runtime.AgentInstance = this;
3737
this.EventTypes = eventTypes;
3838
_logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<AgentBase>();
39+
var subscriptionRequest = new AddSubscriptionRequest
40+
{
41+
RequestId = Guid.NewGuid().ToString(),
42+
Subscription = new Subscription
43+
{
44+
TypeSubscription = new TypeSubscription
45+
{
46+
AgentType = this.AgentId.Type,
47+
TopicType = this.AgentId.Type + "/" + this.AgentId.Key
48+
}
49+
}
50+
};
51+
_runtime.SendMessageAsync(new Message { AddSubscriptionRequest = subscriptionRequest }).AsTask().Wait();
3952
Completion = Start();
4053
}
4154
internal Task Completion { get; }
@@ -131,19 +144,19 @@ public List<string> Subscribe(string topic)
131144
}
132145
}
133146
};
134-
_context.SendMessageAsync(message).AsTask().Wait();
147+
_runtime.SendMessageAsync(message).AsTask().Wait();
135148

136149
return new List<string> { topic };
137150
}
138151
public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
139152
{
140-
await _context.StoreAsync(state, cancellationToken).ConfigureAwait(false);
153+
await _runtime.StoreAsync(state, cancellationToken).ConfigureAwait(false);
141154
return;
142155
}
143156
public async Task<T> ReadAsync<T>(AgentId agentId, CancellationToken cancellationToken = default) where T : IMessage, new()
144157
{
145-
var agentState = await _context.ReadAsync(agentId, cancellationToken).ConfigureAwait(false);
146-
return agentState.FromAgentState<T>();
158+
var agentstate = await _runtime.ReadAsync(agentId, cancellationToken).ConfigureAwait(false);
159+
return agentstate.FromAgentState<T>();
147160
}
148161
private void OnResponseCore(RpcResponse response)
149162
{
@@ -171,7 +184,7 @@ private async Task OnRequestCoreAsync(RpcRequest request, CancellationToken canc
171184
{
172185
response = new RpcResponse { Error = ex.Message };
173186
}
174-
await _context.SendResponseAsync(request, response, cancellationToken).ConfigureAwait(false);
187+
await _runtime.SendResponseAsync(request, response, cancellationToken).ConfigureAwait(false);
175188
}
176189

177190
protected async Task<RpcResponse> RequestAsync(AgentId target, string method, Dictionary<string, string> parameters)
@@ -195,7 +208,7 @@ protected async Task<RpcResponse> RequestAsync(AgentId target, string method, Di
195208
activity?.SetTag("peer.service", target.ToString());
196209

197210
var completion = new TaskCompletionSource<RpcResponse>(TaskCreationOptions.RunContinuationsAsynchronously);
198-
_context.Update(request, activity);
211+
_runtime.Update(request, activity);
199212
await this.InvokeWithActivityAsync(
200213
static async ((AgentBase Agent, RpcRequest Request, TaskCompletionSource<RpcResponse>) state, CancellationToken ct) =>
201214
{
@@ -206,7 +219,7 @@ static async ((AgentBase Agent, RpcRequest Request, TaskCompletionSource<RpcResp
206219
self._pendingRequests[request.RequestId] = completion;
207220
}
208221

209-
await state.Agent._context.SendRequestAsync(state.Agent, state.Request, ct).ConfigureAwait(false);
222+
await state.Agent._runtime.SendRequestAsync(state.Agent, state.Request).ConfigureAwait(false);
210223

211224
await completion.Task.ConfigureAwait(false);
212225
},
@@ -231,11 +244,11 @@ public async ValueTask PublishEventAsync(CloudEvent item, CancellationToken canc
231244
activity?.SetTag("peer.service", $"{item.Type}/{item.Source}");
232245

233246
// TODO: fix activity
234-
_context.Update(item, activity);
247+
_runtime.Update(item, activity);
235248
await this.InvokeWithActivityAsync(
236249
static async ((AgentBase Agent, CloudEvent Event) state, CancellationToken ct) =>
237250
{
238-
await state.Agent._context.PublishEventAsync(state.Event, ct).ConfigureAwait(false);
251+
await state.Agent._runtime.PublishEventAsync(state.Event).ConfigureAwait(false);
239252
},
240253
(this, item),
241254
activity,

dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorker.cs

+27-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class AgentWorker :
2424
private readonly CancellationTokenSource _shutdownCts;
2525
private readonly IServiceProvider _serviceProvider;
2626
private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes;
27+
private readonly ConcurrentDictionary<string, Subscription> _subscriptionsByAgentType = new();
28+
private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
2729
private readonly DistributedContextPropagator _distributedContextPropagator;
2830
private readonly CancellationTokenSource _shutdownCancellationToken = new();
2931
private Task? _mailboxTask;
@@ -96,11 +98,7 @@ public async Task RunMessagePump()
9698
if (message == null) { continue; }
9799
switch (message)
98100
{
99-
case Message.MessageOneofCase.AddSubscriptionResponse:
100-
break;
101-
case Message.MessageOneofCase.RegisterAgentTypeResponse:
102-
break;
103-
case Message msg:
101+
case Message msg when msg.CloudEvent != null:
104102

105103
var item = msg.CloudEvent;
106104

@@ -110,6 +108,13 @@ public async Task RunMessagePump()
110108
agentToInvoke.ReceiveMessage(msg);
111109
}
112110
break;
111+
case Message msg when msg.AddSubscriptionRequest != null:
112+
await AddSubscriptionRequestAsync(msg.AddSubscriptionRequest).ConfigureAwait(true);
113+
break;
114+
case Message msg when msg.AddSubscriptionResponse != null:
115+
break;
116+
case Message msg when msg.RegisterAgentTypeResponse != null:
117+
break;
113118
default:
114119
throw new InvalidOperationException($"Unexpected message '{message}'.");
115120
}
@@ -123,6 +128,23 @@ public async Task RunMessagePump()
123128
}
124129
}
125130
}
131+
private async ValueTask AddSubscriptionRequestAsync(AddSubscriptionRequest subscription)
132+
{
133+
var topic = subscription.Subscription.TypeSubscription.TopicType;
134+
var agentType = subscription.Subscription.TypeSubscription.AgentType;
135+
_subscriptionsByAgentType[agentType] = subscription.Subscription;
136+
_subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
137+
Message response = new()
138+
{
139+
AddSubscriptionResponse = new()
140+
{
141+
RequestId = subscription.RequestId,
142+
Error = "",
143+
Success = true
144+
}
145+
};
146+
await _mailbox.Writer.WriteAsync(response).ConfigureAwait(false);
147+
}
126148

127149
public async Task StartAsync(CancellationToken cancellationToken)
128150
{

dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcGateway.cs

+16
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,22 @@ private async ValueTask RegisterAgentTypeAsync(GrpcWorkerConnection connection,
153153
Success = true
154154
}
155155
};
156+
// add a default subscription for the agent type
157+
//TODO: we should consider having constraints on the namespace or at least migrate all our examples to use well typed namesspaces like com.microsoft.autogen/hello/HelloAgents etc
158+
var subscriptionRequest = new AddSubscriptionRequest
159+
{
160+
RequestId = Guid.NewGuid().ToString(),
161+
Subscription = new Subscription
162+
{
163+
TypeSubscription = new TypeSubscription
164+
{
165+
AgentType = msg.Type,
166+
TopicType = msg.Type
167+
}
168+
}
169+
};
170+
await AddSubscriptionAsync(connection, subscriptionRequest).ConfigureAwait(true);
171+
156172
await connection.ResponseStream.WriteAsync(response).ConfigureAwait(false);
157173
}
158174
private async ValueTask DispatchEventAsync(CloudEvent evt)

dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentBaseTests.cs

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ public class AgentBaseTests(InMemoryAgentRuntimeFixture fixture)
2323
public async Task ItInvokeRightHandlerTestAsync()
2424
{
2525
var mockContext = new Mock<IAgentRuntime>();
26+
mockContext.SetupGet(x => x.AgentId).Returns(new AgentId("test", "test"));
27+
// mock SendMessageAsync
28+
mockContext.Setup(x => x.SendMessageAsync(It.IsAny<Message>(), It.IsAny<CancellationToken>()))
29+
.Returns(new ValueTask());
2630
var agent = new TestAgent(mockContext.Object, new EventTypes(TypeRegistry.Empty, [], []), new Logger<AgentBase>(new LoggerFactory()));
2731

2832
await agent.HandleObject("hello world");

protos/agent_worker.proto

+6
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,15 @@ message TypeSubscription {
6363
string agent_type = 2;
6464
}
6565

66+
message TypePrefixSubscription {
67+
string topic_type_prefix = 1;
68+
string agent_type = 2;
69+
}
70+
6671
message Subscription {
6772
oneof subscription {
6873
TypeSubscription typeSubscription = 1;
74+
TypePrefixSubscription typePrefixSubscription = 2;
6975
}
7076
}
7177

python/README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# AutoGen Python packages
22

3-
See [`autogen-core`](./packages/autogen-core/) package for main functionality.
3+
[![0.4 Docs](https://img.shields.io/badge/Docs-0.4-blue)](https://microsoft.github.io/autogen/dev/)
4+
[![PyPi autogen-core](https://img.shields.io/badge/PyPi-autogen--core-blue?logo=pypi)](https://pypi.org/project/autogen-core/0.4.0.dev7/) [![PyPi autogen-agentchat](https://img.shields.io/badge/PyPi-autogen--agentchat-blue?logo=pypi)](https://pypi.org/project/autogen-agentchat/0.4.0.dev7/) [![PyPi autogen-ext](https://img.shields.io/badge/PyPi-autogen--ext-blue?logo=pypi)](https://pypi.org/project/autogen-ext/0.4.0.dev7/)
45

56

7+
This directory works as a single `uv` workspace containing all project packages. See [`packages`](./packages/) to discover all project packages.
8+
69
## Development
710

811
**TL;DR**, run all checks with:

python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ def _handoff_tool() -> str:
8282
class AssistantAgent(BaseChatAgent):
8383
"""An agent that provides assistance with tool use.
8484
85-
It responds with a StopMessage when 'terminate' is detected in the response.
86-
8785
Args:
8886
name (str): The name of the agent.
8987
model_client (ChatCompletionClient): The model client to use for inference.
9088
tools (List[Tool | Callable[..., Any] | Callable[..., Awaitable[Any]]] | None, optional): The tools to register with the agent.
91-
handoffs (List[Handoff | str] | None, optional): The handoff configurations for the agent, allowing it to transfer to other agents by responding with a HandoffMessage.
89+
handoffs (List[Handoff | str] | None, optional): The handoff configurations for the agent,
90+
allowing it to transfer to other agents by responding with a :class:`HandoffMessage`.
91+
The transfer is only executed when the team is in :class:`~autogen_agentchat.teams.Swarm`.
9292
If a handoff is a string, it should represent the target agent's name.
9393
description (str, optional): The description of the agent.
9494
system_message (str, optional): The system message for the model.

0 commit comments

Comments
 (0)