Refactor documentation pages and Add core concept page. (#140)

This commit is contained in:
Eric Zhu 2024-06-28 14:15:51 -07:00 committed by GitHub
parent ebed669231
commit 4023f13b5f
17 changed files with 517 additions and 177 deletions

View File

@ -1,16 +1,4 @@
# Memory
Memory is a collection of data corresponding to the conversation history
of an agent.
Data in meory can be just a simple list of all messages,
or one which provides a view of the last N messages.
To create a custom memory implementation, you need to subclass the
{py:class}`agnext.components.memory.ChatMemory` protocol class and implement
all its methods.
For example, you can use [LLMLingua](https://github.com/microsoft/LLMLingua)
to create a custom memory implementation that provides a compressed
view of the conversation history.
# Buffered Memory
Here is an example of a custom memory implementation that keeps a view of the
last N messages:

View File

@ -1,69 +0,0 @@
# Agent
An agent in AGNext is an entity that can react to, send, and publish
messages. Messages are the only means through which agents can communicate
with each other.
## Messages
Messages are typed, and serializable (to JSON) objects that agents use to communicate. The type of a message is used to determine which agents a message should be delivered to, if an agent can handle a message and the handler that should be invoked when the message is received by an agent. If an agent is invoked with a message it is not able to handle, it must raise {py:class}`~agnext.core.exceptions.CantHandleException`.
Generally, messages are one of:
- A subclass of Pydantic's {py:class}`pydantic.BaseModel`
- A dataclass
Messages are purely data, and should not contain any logic.
```{tip}
It is *strongly* recommended that messages are Pydantic models. This allows for easy serialization and deserialization of messages, and provides a clear schema for the message.
```
<!-- ### Required Message Types
At the core framework level there is *no requirement* of which message types are handled by an agent. However, some behavior patterns require agents understand certain message types. For an agent to participate in these patterns, it must understand any such required message types.
For example, the chat layer in AGNext has the following required message types:
- {py:class}`agnext.chat.types.PublishNow`
- {py:class}`agnext.chat.types.Reset`
These are purely behavioral messages that are used to control the behavior of agents in the chat layer and do not represent any content.
Agents should document which message types they can handle. Orchestrating agents should document which message types they require.
```{tip}
An important part of designing an agent or choosing which agents to use is understanding which message types are required by the agents you are using.
``` -->
## Communication
There are two forms of communication in AGNext:
- **Direct communication**: An agent sends a direct message to another agent.
- **Broadcast communication**: An agent publishes a message to all agents in the same namespace.
### Message Handling
When an agent receives a message the runtime will invoke the agent's message handler ({py:meth}`agnext.core.Agent.on_message`) which should implement the agents message handling logic. If this message cannot be handled by the agent, the agent should raise a {py:class}`~agnext.core.exceptions.CantHandleException`. For the majority of custom agent's {py:meth}`agnext.core.Agent.on_message` will not be directly implemented, but rather the agent will use the {py:class}`~agnext.components.TypeRoutedAgent` base class which provides a simple API for associating message types with message handlers.
### Direct Communication
Direct communication is effectively an RPC call directly to another agent. When sending a direct message to another agent, the receiving agent can respond to the message with another message, or simply return `None`. To send a message to another agent, within a message handler use the {py:meth}`agnext.core.BaseAgent.send_message` method. Awaiting this call will return the response of the invoked agent. If the receiving agent raises an exception, this will be propagated back to the sending agent.
To send a message to an agent outside of agent handling a message the message should be sent via the runtime with the {py:meth}`agnext.core.AgentRuntime.send_message` method. This is often how an application might "start" a workflow or conversation.
### Broadcast Communication
Broadcast communication is effectively the publish-subscribe model.
As part of the agent's implementation it must advertise the message types that it would like to receive when published ({py:attr}`agnext.core.Agent.subscriptions`). If one of these messages is published, the agent's message handler will be invoked. The key difference between direct and broadcast communication is that broadcast communication is not a request/response model. When an agent publishes a message it is one way, it is not expecting a response from any other agent. In fact, they cannot respond to the message.
To publish a message to all agents, use the {py:meth}`agnext.core.BaseAgent.publish_message` method. This call must still be awaited to allow the runtime to deliver the message to all agents, but it will always return `None`. If an agent raises an exception while handling a published message, this will be logged but will not be propagated back to the publishing agent.
To publish a message to all agents outside of an agent handling a message, the message should be published via the runtime with the {py:meth}`agnext.core.AgentRuntime.publish_message` method.
If an agent publishes a message type for which it is subscribed it will not receive the message it published. This is to prevent infinite loops.
```{note}
Currently an agent does not know if it is handling a published or direct message. So, if a response is given to a published message, it will be thrown away.
```

View File

@ -1 +0,0 @@
# Cancellation

View File

@ -1,19 +0,0 @@
# Namespace
Namespace allow for defining logical boundaries between agents.
Namespaces are strings, and the default is `default`.
Two possible use cases of agents are:
- Creating a multi-tenant system where each tenant has its own namespace. For
example, a chat system where each tenant has its own set of agents.
- Security boundaries between agent groups. For example, a chat system where
agents in the `admin` namespace can communicate with agents in the `user`
namespace, but not the other way around.
The {py:class}`agnext.core.AgentId` is used to address an agent, it is the combination of the agent's namespace and its name.
When getting an agent reference ({py:meth}`agnext.core.AgentRuntime.get`) or proxy ({py:meth}`agnext.core.AgentRuntime.get_proxy`) from the runtime the namespace can be specified. Agents have an ID property ({py:attr}`agnext.core.Agent.id`) that returns the agent's id. Additionally, the register method takes a factory that can optionally accept the ID as an argument ({py:meth}`agnext.core.AgentRuntime.register`).
By default, there are no restrictions and are left to the application to enforce. The runtime will however automatically create agents in a namespace if it does not exist.

View File

@ -1,36 +0,0 @@
# Agent Runtime
Agent runtime is the execution environment for agents in AGNext.
Similar to the runtime environment of a programming language, the
agent runtime provides the necessary infrastructure to facilitate communication
between agents, manage agent states, and provide API for monitoring and
debugging multi-agent interactions.
Further readings:
1. {py:class}`agnext.core.AgentRuntime`
2. {py:class}`agnext.application.SingleThreadedAgentRuntime`
## Agent Registration
Agents are registered with the runtime using the
{py:meth}`agnext.core.AgentRuntime.register` method. The process of registration
associates some name, which is the `type` of the agent with a factory function
that is able to create an instance of the agent in a given namespace. The reason
for the factory function is to allow automatic creation of agents when they are
needed, including automatic creation of agents for not yet existing namespaces.
Once an agent is registered, a reference to the agent can be retrieved by
calling {py:meth}`agnext.core.AgentRuntime.get` or
{py:meth}`agnext.core.AgentRuntime.get_proxy`. There is a convenience method
{py:meth}`agnext.core.AgentRuntime.register_and_get` that both registers a type
and gets a reference.
A byproduct of this process of `register` + `get` is that
{py:class}`agnext.core.Agent` interface is a purely implementation contract. All
agents must be communicated with via the runtime. This is a key design decision
that allows the runtime to manage the lifecycle of agents, and to provide a
consistent API for interacting with agents. Therefore, to communicate with
another agent the {py:class}`agnext.core.AgentId` must be used. There is a
convenience class {py:meth}`agnext.core.AgentProxy` that bundles an ID and a
runtime together.

View File

@ -1,8 +0,0 @@
# Tools
Tools can be used together with agents powered by the OpenAI's ChatCompletion or the Assistant API.
AGNext provides the {py:mod}`agnext.components.tools` module with a suite of built-in
tools and utilities for creating and running custom tools.
See [examples](https://github.com/microsoft/agnext/tree/main/python/examples#tool-use-examples)
for how to use the built-in code execution tool and creating custom tools.

View File

@ -0,0 +1,456 @@
# Core Concepts
## What is Multi-Agent Application?
A wide variety of software applications can be modeled as a collection of independent
agents that communicate with each other through messages:
sensors on a factory floor,
distributed services powering web applications,
business workflows involving multiple stakeholders,
and more recently, generative artificial intelligence (AI) models (e.g., GPT-4) that can write code and interact with
other software systems.
We refer to them as multi-agent applications.
In a multi-agent application, agents can live in the same process, on the same machine,
or on different machines and across organizational boundaries.
They can be implemented using different AI models, instructions, and programming languages.
They can collaborate and work toward a common goal.
Each agent is a self-contained unit:
developers can build, test and deploy it independently, and reuse it for different scenarios.
Agents are composable: simple agents can form complex applications.
## AGNext Overview
AGNext is a framework for building multi-agent applications.
It provides a runtime envionment to facilitate communication between agents,
manage their identities and lifecycles, and enforce boundaries.
It also provides a set of common patterns and components to help developers build
AI agents that can work together.
AGNext is designed to be unopinionated and extensible.
It does not prescribe an abstraction for agents or messages, rather, it provides
a minimal base layer that can be extended to suit the application's needs.
Developers can build agents quickly by using the provided components including
type-routed agent, AI model clients, tools for AI models, code execution sandboxes,
memory stores, and more.
Developers can also make use of the provided multi-agent patterns to build
orchestrated workflows, group chat systems, and more.
The API consists of the following modules:
- {py:mod}`agnext.core` - The core interfaces that defines agent and runtime.
- {py:mod}`agnext.application` - Implementations of the runtime and other modules (e.g., logging) for building applications.
- {py:mod}`agnext.components` - Independent agent-building components: agents, models, memory, and tools.
## Agent and Agent Runtime
An agent in AGNext is an entity that can react to, send, and publish
messages. Messages are the only means through which agents can communicate
with each other.
An agent runtime is the execution environment for agents in AGNext.
Similar to the runtime environment of a programming language, the
agent runtime provides the necessary infrastructure to facilitate communication
between agents, manage agent lifecycles, enforce security boundaries, and support monitoring and
debugging.
For local development, developers can use {py:class}`~agnext.application.SingleThreadedAgentRuntime`,
which can be embedded in a Python application.
```{note}
Agents are not directly instantiated and managed by application code.
Instead, they are created by the runtime when needed and managed by the runtime.
```
### Implementing an Agent
To implement an agent, developer must subclass the {py:class}`~agnext.core.BaseAgent` class,
declare the message types it can handle in the {py:attr}`~agnext.core.AgentMetadata.subscriptions` metadata,
and implement the {py:meth}`~agnext.core.BaseAgent.on_message` method.
This method is invoked when the agent receives a message. For example,
the following agent handles string messages and simply prints message it receives:
```python
from agnext.core import BaseAgent, CancellationToken
class MyAgent(BaseAgent):
def __init__(self):
super().__init__("MyAgent", subscriptions=[str])
async def on_message(self, message: str, cancellation_token: CancellationToken) -> None:
print(f"Received message: {message}")
```
For convenience, developers can subclass the {py:class}`~agnext.components.TypeRoutedAgent` class
which provides an easy-to use API to implement different message handlers for different message types.
See the section on message handlers below.
### Registering Agents
To make an agent available to the runtime, developers can use the
{py:meth}`~agnext.core.AgentRuntime.register` method.
The process of registration associates a name and a factory function
that creates an instance of the agent in a given namespace.
The factory function is used to allow automatic creation of agents when they are needed.
For example, to register an agent with the {py:class}`~agnext.application.SingleThreadedAgentRuntime`,
the following code can be used:
```python
from agnext.application import SingleThreadedAgentRuntime
runtime = SingleThreadedAgentRuntime()
runtime.register("my_agent", lambda: MyAgent())
```
Once an agent is registered, a reference to the agent can be retrieved by
calling {py:meth}`~agnext.core.AgentRuntime.get` or
{py:meth}`~agnext.core.AgentRuntime.get_proxy`. For example, to
send a message to the agent we just registered:
```python
agent = runtime.get("my_agent")
await runtime.send_message("Hello, World!", agent)
```
There is a convenience method
{py:meth}`~agnext.core.AgentRuntime.register_and_get` that both registers an agent
and gets a reference.
```{note}
Because the runtime manages the lifecycle of agents, a reference to an agent,
whether it is {py:class}`~agnext.core.AgentId` or {py:class}`~agnext.core.AgentProxy`,
is only used to communicate with the agent or retrieve its metadata (e.g., description).
```
### Running the Agent Runtime
The above code snippets will not actually produce any output because the
runtime is not running.
The local embedded runtime {py:class}`~agnext.application.SingleThreadedAgentRuntime`
can be called to process messages until there are no more messages to process.
```python
await runtime.process_until_idle()
```
It can also be called to process a single message:
```python
await runtime.process_next()
```
Other runtime implementations will have their own way of running the runtime.
## Messages
Agents communicate with each other via messages.
Messages are serializable objects, they can be defined using:
- A subclass of Pydantic's {py:class}`pydantic.BaseModel`, or
- A dataclass
- A built-in serializable Python type (e.g., `str`).
For example:
```python
from dataclasses import dataclass
@dataclass
class TextMessage:
content: str
source: str
@dataclass
class ImageMessage:
url: str
source: str
```
```{note}
Messages are purely data, and should not contain any logic.
```
### Message Handlers
When an agent receives a message the runtime will invoke the agent's message handler
({py:meth}`~agnext.core.Agent.on_message`) which should implement the agents message handling logic.
If this message cannot be handled by the agent, the agent should raise a
{py:class}`~agnext.core.exceptions.CantHandleException`.
For convenience, the {py:class}`~agnext.components.TypeRoutedAgent` base class
provides a simple API for associating message types with message handlers,
so developers do not need to implement the {py:meth}`~agnext.core.Agent.on_message` method.
For example, the following type-routed agent responds to `TextMessage` and `ImageMessage`
using different message handlers:
```python
from agnext.application import SingleThreadedAgentRuntime
from agnext.components import TypeRoutedAgent, message_handler
from agnext.core import CancellationToken
class MyAgent(TypeRoutedAgent):
@message_handler
async def on_text_message(self, message: TextMessage, cancellation_token: CancellationToken) -> None:
print(f"Hello, {message.source}, you said {message.content}!")
@message_handler
async def on_image_message(self, message: ImageMessage, cancellation_token: CancellationToken) -> None:
print(f"Hello, {message.source}, you sent me {message.url}!")
async def main() -> None:
runtime = SingleThreadedAgentRuntime()
agent = runtime.register_and_get("my_agent", lambda: MyAgent("My Agent"))
await runtime.send_message(TextMessage(content="Hello, World!", source="User"), agent)
await runtime.send_message(ImageMessage(url="https://example.com/image.jpg", source="User"), agent)
runtime.process_until_idle()
import asyncio
asyncio.run(main())
```
## Communication
There are two types of communication in AGNext:
- **Direct communication**: An agent sends a direct message to another agent.
- **Broadcast communication**: An agent publishes a message to all agents in the same namespace.
### Direct Communication
To send a direct message to another agent, within a message handler use
the {py:meth}`agnext.core.BaseAgent.send_message` method,
from the runtime use the {py:meth}`agnext.core.AgentRuntime.send_message` method.
Awaiting this method call will return the a `Future[T]` object where `T` is the type
of response of the invoked agent.
The future object can be awaited to get the actual response.
```{note}
If the invoked agent raises an exception while the sender is awaiting on
the future, the exception will be propagated back to the sender.
```
#### Request/Response
Direct communication can be used for request/response scenarios,
where the sender expects a response from the receiver.
The receiver can respond to the message by returning a value from its message handler.
You can think of this as a function call between agents.
For example, consider the following type-routed agents:
```python
from agnext.application import SingleThreadedAgentRuntime
from agnext.components import TypeRoutedAgent, message_handler
from agnext.core import CancellationToken, AgentId
class InnerAgent(TypeRoutedAgent):
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> str:
return f"Hello from inner, {message}"
class OuterAgent(TypeRoutedAgent):
def __init__(self, inner_agent_id: AgentId):
super().__init__("OuterAgent")
self.inner_agent_id = inner_agent_id
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> None:
print(f"Received message: {message}")
# Send a direct message to the inner agent and receves a response future.
response_future = await self.send_message(f"Hello from outer, {message}", self.inner_agent_id)
# Wait for the response to be ready.
response = await response_future
print(f"Received inner response: {response}")
async def main() -> None:
runtime = SingleThreadedAgentRuntime()
inner = runtime.register_and_get("inner_agent", lambda: InnerAgent("InnerAgent"))
outer = runtime.register_and_get("outer_agent", lambda: OuterAgent("OuterAgent", inner))
await runtime.send_message("Hello, World!", outer)
runtime.process_until_idle()
import asyncio
asyncio.run(main())
```
In the above example, upone receving a message,
the `OuterAgent` sends a direct string message to the `InnerAgent` and receives
a string message in response. The following output will be produced:
```text
Received message: Hello, World!
Received inner response: Hello from inner, Hello from outer, Hello, World!
```
```{note}
To get the response after sending a message, the sender must await on the
response future. So you can also write `response = await await self.send_message(...)`.
```
#### Send, No Reply
In many scenarios, the sender does not need a response from the receiver.
In this case, the sender does not need to await on the response future,
and the receiver does not need to return a value from the message handler.
In the following example, the `InnerAgent` does not return a value,
and the `OuterAgent` does not await on the response future:
```python
from agnext.application import SingleThreadedAgentRuntime
from agnext.components import TypeRoutedAgent, message_handler
from agnext.core import CancellationToken, AgentId
class InnerAgent(TypeRoutedAgent):
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> None:
# Just print the message.
print(f"Hello from inner, {message}")
class OuterAgent(TypeRoutedAgent):
def __init__(self, inner_agent_id: AgentId):
super().__init__("OuterAgent")
self.inner_agent_id = inner_agent_id
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> None:
print(f"Received message: {message}")
# Send a direct message to the inner agent and move on.
await self.send_message(f"Hello from outer, {message}", self.inner_agent_id)
# No need to wait for the response, just do other things.
async def main() -> None:
runtime = SingleThreadedAgentRuntime()
inner = runtime.register_and_get("inner_agent", lambda: InnerAgent("InnerAgent"))
outer = runtime.register_and_get("outer_agent", lambda: OuterAgent("OuterAgent", inner))
await runtime.send_message("Hello, World!", outer)
runtime.process_until_idle()
import asyncio
asyncio.run(main())
```
In the above example, the `OuterAgent` sends a direct string message to the `InnerAgent`
but does not await on the response future. The following output will be produced:
```text
Received message: Hello, World!
Hello from inner, Hello from outer, Hello, World!
```
### Broadcast Communication
Broadcast communication is effectively the publish/subscribe model.
As part of the base agent ({py:class}`~agnext.core.BaseAgent`) implementation,
it must advertise the message types that
it would like to receive when published ({py:attr}`~agnext.core.AgentMetadata.subscriptions`).
If one of these messages is published, the agent's message handler will be invoked.
The key difference between direct and broadcast communication is that broadcast
communication cannot be used for request/response scenarios.
When an agent publishes a message it is one way only, it cannot receive a response
from any other agent, even if a receiving agent sends a response.
```{note}
An agent receiving a message does not know if it is handling a published or direct message.
So, if a response is given to a published message, it will be thrown away.
```
To publish a message to all agents in the same namespace,
use the {py:meth}`agnext.core.BaseAgent.publish_message` method.
This call must still be awaited to allow the runtime to deliver the message to all agents,
but it will always return `None`.
If an agent raises an exception while handling a published message,
this will be logged but will not be propagated back to the publishing agent.
The following example shows a `BroadcastingAgent` that publishes a message
upong receiving a string message. A `ReceivingAgent` that prints the message
it receives.
```python
from agnext.application import SingleThreadedAgentRuntime
from agnext.components import TypeRoutedAgent, message_handler
from agnext.core import CancellationToken
class BroadcastingAgent(TypeRoutedAgent):
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> None:
# Publish a message to all agents in the same namespace.
await self.publish_message(f"Publishing a message: {message}!")
class ReceivingAgent(TypeRoutedAgent):
@message_handler
async def on_str_message(self, message: str, cancellation_token: CancellationToken) -> None:
print(f"Received a message: {message}")
async def main() -> None:
runtime = SingleThreadedAgentRuntime()
broadcaster = runtime.register_and_get("broadcasting_agent", lambda: BroadcastingAgent("Broadcasting Agent"))
runtime.register("receiving_agent", lambda: ReceivingAgent("Receiving Agent"))
await runtime.send_message("Hello, World!", broadcaster)
runtime.process_until_idle()
import asyncio
asyncio.run(main())
```
Running the above code will produce the following output produced by the `ReceivingAgent`:
```text
Received a message: Publishing a message: Hello, World!
```
To publish a message to all agents outside of an agent handling a message,
the message should be published via the runtime with the
{py:meth}`agnext.core.AgentRuntime.publish_message` method.
```python
await runtime.publish_message("Hello, World! From the runtime!", namespace="default")
runtime.process_until_idle()
```
Running the above code will produce the following output:
```text
Received a message: Hello, World! From the runtime!
Received a message: Publishing a message: Hello, World! From the runtime!
```
The first output is from the `ReceivingAgent` that received a message published
by the runtime. The second output is from the `ReceivingAgent` that received
a message published by the `BroadcastingAgent`.
```{note}
If an agent publishes a message type for which it is subscribed it will not
receive the message it published. This is to prevent infinite loops.
```
## Namespace
Namespace allow for defining logical boundaries between agents.
Namespaces are strings, and the default is `default`.
Two possible use cases of agents are:
- Creating a multi-tenant system where each tenant has its own namespace. For
example, a chat system where each tenant has its own set of agents.
- Security boundaries between agent groups. For example, a chat system where
agents in the `admin` namespace can communicate with agents in the `user`
namespace, but not the other way around.
The {py:class}`~agnext.core.AgentId` is used to address an agent,
it is the combination of the agent's namespace and its name.
When getting an agent reference ({py:meth}`agnext.core.AgentRuntime.get`) or
proxy ({py:meth}`agnext.core.AgentRuntime.get_proxy`) from the runtime the
namespace can be specified.
Agents have an ID property ({py:attr}`agnext.core.Agent.id`) that returns the
agent's id.
Additionally, the register method takes a factory that can optionally accept
the ID as an argument ({py:meth}`agnext.core.AgentRuntime.register`).
By default, there are no restrictions and are left to the application to
enforce. The runtime will however automatically create agents in a
namespace if it does not exist.

View File

@ -1 +0,0 @@
# Tutorial

View File

@ -0,0 +1,37 @@
# Agent Components
AGNext provides a suite of components to help developers build agents.
## Type-Routed Agent
The {py:class}`~agnext.components.TypeRoutedAgent` base class provides
developer with a simple decorator {py:meth}`~agnext.components.message_handler`
for associating message types with message handlers.
## Model Clients
AGNext provides the {py:mod}`agnext.components.models` module with a suite of built-in
model clients for using ChatCompletion API.
## Tools
Tools can be used together with agents powered by the OpenAI's ChatCompletion or the Assistant API.
AGNext provides the {py:mod}`agnext.components.tools` module with a suite of built-in
tools and utilities for creating and running custom tools.
See [examples](https://github.com/microsoft/agnext/tree/main/python/examples#tool-use-examples)
for how to use the built-in code execution tool and creating custom tools.
## Memory
Memory is a collection of data corresponding to the conversation history
of an agent.
Data in meory can be just a simple list of all messages,
or one which provides a view of the last N messages.
To create a custom memory implementation, you need to subclass the
{py:class}`agnext.components.memory.ChatMemory` protocol class and implement
all its methods.
For example, you can use [LLMLingua](https://github.com/microsoft/LLMLingua)
to create a custom memory implementation that provides a compressed
view of the conversation history.

View File

@ -8,7 +8,6 @@ multi-agent systems out-performing single agent systems at complex tasks
like software development.
You can implement any multi-agent pattern using AGNext agents, which
communicate with each other using messages through the agent runtime
(see {doc}`/core-concepts/runtime` and {doc}`/core-concepts/agent`).
communicate with each other using messages through the agent runtime.
See [examples](https://github.com/microsoft/agnext/tree/main/python/examples#pattern-examples)
for how to implement patterns like reflection and group chat.

View File

@ -3,18 +3,16 @@ AGNext
AGNext is a framework for building multi-agent applications.
At a high level, it provides a framework for inter-agent communication and a
suite of independent components for building and managing agents. It models agents as
independent actors communicating via messages. You can implement agents in
different languages and run them on different machines across organizational boundaries.
At a high level, it provides a framework for inter-agent communication and a
suite of independent components for building and managing agents.
You can implement agents in
different programming languages and run them on different machines across organizational boundaries.
You can also implement agents using other agent frameworks and run them in AGNext.
:doc:`Agents <core-concepts/agent>` are hosted by and managed by a :doc:`runtime <core-concepts/runtime>`.
AGNext supports both RPC-like direct messaging and event based
communication between agents, allowing for a :doc:`diverse set of agent patterns
<core-concepts/patterns>`.
Please read :doc:`Core Concepts <getting-started/core-concepts>` for
a detailed overview of AGNext's architecture and design.
AGNext's developer API consists of the following layers:
AGNext's API consists of the following modules:
- :doc:`core <reference/agnext.core>` - The core interfaces that defines agent and runtime.
- :doc:`application <reference/agnext.application>` - Implementations of the runtime and other modules (e.g., logging) for building applications.
@ -29,30 +27,26 @@ that demonstrate how to use AGNext.
:hidden:
getting-started/installation
getting-started/tutorial
.. toctree::
:caption: Core Concepts
:hidden:
core-concepts/runtime
core-concepts/agent
core-concepts/patterns
core-concepts/memory
core-concepts/tools
core-concepts/cancellation
core-concepts/logging
core-concepts/namespace
core-concepts/worker_protocol
getting-started/core-concepts
.. toctree::
:caption: Guides
:hidden:
guides/type-routed-agent
guides/azure-openai-with-aad-auth
guides/termination-with-intervention
guides/extracting-results-with-an-agent
guides/components
guides/patterns
guides/logging
guides/worker-protocol
.. toctree::
:caption: Cookbook
:hidden:
cookbook/type-routed-agent
cookbook/azure-openai-with-aad-auth
cookbook/termination-with-intervention
cookbook/buffered-memory
cookbook/extracting-results-with-an-agent
.. toctree::