Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task-Centric Memory #5227

Open
wants to merge 134 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 130 commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
442a9d8
initial checkin
rickyloynd-microsoft Nov 29, 2024
f8584cd
support for extensive evaluations
rickyloynd-microsoft Dec 2, 2024
607e7ff
Enhance retrieval with task generalization and insight validation
rickyloynd-microsoft Dec 4, 2024
b045636
Support TRAPI client.
rickyloynd-microsoft Dec 9, 2024
63b28d7
Restoring earlier results, and general cleanup.
rickyloynd-microsoft Dec 24, 2024
b921d83
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Dec 24, 2024
9dfb074
Modify imports after merge from main.
rickyloynd-microsoft Dec 24, 2024
93a5ca4
Log model and token counts.
rickyloynd-microsoft Dec 26, 2024
2cb9344
Only instantiate the client once.
rickyloynd-microsoft Dec 26, 2024
878f458
Fix bug that was duplicating insights across trials.
rickyloynd-microsoft Dec 26, 2024
21562f1
Add the Grader class.
rickyloynd-microsoft Dec 27, 2024
3a40b30
Adjustments for comparison tests.
rickyloynd-microsoft Dec 28, 2024
8622c5e
Test generalization over multiple tasks.
rickyloynd-microsoft Dec 30, 2024
20b26c1
Add teachability and a test for it.
rickyloynd-microsoft Dec 31, 2024
9d47227
Learning from demonstration, in-progress.
rickyloynd-microsoft Jan 1, 2025
52d4e00
In memory retrieval, validate insights separately rather than together.
rickyloynd-microsoft Jan 1, 2025
6b15777
Finish learning from demonstration.
rickyloynd-microsoft Jan 2, 2025
a18674c
Added RecordableChatCompletionClient as a guardrail during refactoring.
rickyloynd-microsoft Jan 3, 2025
52e213e
Ran 3 evals with session recording and replay.
rickyloynd-microsoft Jan 5, 2025
a440b0a
Add results to recorded sessions, including session length.
rickyloynd-microsoft Jan 5, 2025
cab51f1
Use yaml file for eval settings.
rickyloynd-microsoft Jan 7, 2025
d91e58c
Simplify paths and other settings.
rickyloynd-microsoft Jan 7, 2025
f1d7a2f
Renamed the memory classes.
rickyloynd-microsoft Jan 7, 2025
17d4c42
Apprentice.
rickyloynd-microsoft Jan 8, 2025
19654e8
Moved test into the evaluator, and removed eval.py's other util funct…
rickyloynd-microsoft Jan 8, 2025
7aa20c1
renaming
rickyloynd-microsoft Jan 8, 2025
83a7ddc
Rerouted calls to AgenticMemoryController through FastLearner.
rickyloynd-microsoft Jan 9, 2025
3047c1c
Replace task_assignment_callback with AgentWrapper.
rickyloynd-microsoft Jan 9, 2025
1f20b79
Segregate files into subfolders, eval framework vs. implementation, etc.
rickyloynd-microsoft Jan 10, 2025
de4c12b
Rename FastLearner subclass to Apprentice, and import it only as spec…
rickyloynd-microsoft Jan 10, 2025
a9d6108
Refactoring, preparatory to removing eval_framework from the branch a…
rickyloynd-microsoft Jan 11, 2025
d67e2cc
Remove the outdated final_format_instructions parameter.
rickyloynd-microsoft Jan 11, 2025
6470fd8
Move tasks into yaml files.
rickyloynd-microsoft Jan 12, 2025
b025199
Move client support to a subdir.
rickyloynd-microsoft Jan 12, 2025
4f9267c
Move evaluations to a separate dir.
rickyloynd-microsoft Jan 12, 2025
db34844
single line
rickyloynd-microsoft Jan 14, 2025
c780852
Add baseline evaluation for the no-memory case.
rickyloynd-microsoft Jan 16, 2025
fa688f7
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Jan 17, 2025
43bda2f
Support o1 models
rickyloynd-microsoft Jan 18, 2025
be081b3
simplification of client creation code
rickyloynd-microsoft Jan 18, 2025
29d1494
simplify folder structure
rickyloynd-microsoft Jan 18, 2025
8e9a550
Move task data strings out of the eval functions.
rickyloynd-microsoft Jan 20, 2025
b3fe084
simplify page_log
rickyloynd-microsoft Jan 21, 2025
077615f
simplify page_log
rickyloynd-microsoft Jan 21, 2025
8847168
simplify page_log
rickyloynd-microsoft Jan 21, 2025
4091ab3
conventional logging terminology
rickyloynd-microsoft Jan 22, 2025
3865cff
control logger enabling
rickyloynd-microsoft Jan 22, 2025
6c73674
add logging to string map
rickyloynd-microsoft Jan 22, 2025
db5e07b
simplify logging
rickyloynd-microsoft Jan 22, 2025
07cb3f0
simplify logging
rickyloynd-microsoft Jan 22, 2025
e88bd69
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Jan 22, 2025
9b3f77d
merge from main
rickyloynd-microsoft Jan 23, 2025
a0dee67
Changes made by poe check.
rickyloynd-microsoft Jan 23, 2025
7e359e9
docstrings etc.
rickyloynd-microsoft Jan 23, 2025
9466ea8
docstrings etc.
rickyloynd-microsoft Jan 24, 2025
4ec9bff
docstrings etc.
rickyloynd-microsoft Jan 24, 2025
76c16f9
docstrings etc.
rickyloynd-microsoft Jan 24, 2025
a8cd0d7
docstrings etc.
rickyloynd-microsoft Jan 24, 2025
ed7fae1
docstrings etc.
rickyloynd-microsoft Jan 25, 2025
93de858
docstrings etc.
rickyloynd-microsoft Jan 25, 2025
1a309f9
docstrings etc.
rickyloynd-microsoft Jan 25, 2025
8993aa1
docstrings etc.
rickyloynd-microsoft Jan 25, 2025
fa60d5a
Simplify naming
rickyloynd-microsoft Jan 25, 2025
882d578
Simplify tests
rickyloynd-microsoft Jan 26, 2025
00cbb8c
standardize logging levels
rickyloynd-microsoft Jan 27, 2025
88294d2
Remove Evaluator class
rickyloynd-microsoft Jan 27, 2025
7d0ed63
sample code
rickyloynd-microsoft Jan 27, 2025
5b3876f
readme
rickyloynd-microsoft Jan 28, 2025
21220d4
readme fixes
rickyloynd-microsoft Jan 28, 2025
232ed0f
samples readme
rickyloynd-microsoft Jan 28, 2025
87ee27b
readme files
rickyloynd-microsoft Jan 28, 2025
b21d140
readme files
rickyloynd-microsoft Jan 28, 2025
1e88eb6
remove ame
rickyloynd-microsoft Jan 28, 2025
a3addc1
readme
rickyloynd-microsoft Jan 28, 2025
c6ffa43
comment out api_key lines
rickyloynd-microsoft Jan 28, 2025
8f66612
Optional disabling of prefix caching (to decorrelate repeated runs)
rickyloynd-microsoft Jan 28, 2025
491964f
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Jan 28, 2025
2ed08ae
Remove unnecessary instantiation of Grader
rickyloynd-microsoft Jan 29, 2025
f879487
Updated image using git-lfs
rickyloynd-microsoft Jan 30, 2025
60f8ad3
Merge branch 'agentic_memory' of github.com:microsoft/autogen into ag…
rickyloynd-microsoft Jan 30, 2025
ed0a4a6
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Jan 30, 2025
f0eceef
installation fixes
rickyloynd-microsoft Jan 30, 2025
70db202
Refactor to remove AgentWrapper, and use AssistantAgent as a TaskRunn…
rickyloynd-microsoft Jan 31, 2025
5e4ad48
uv fixes
rickyloynd-microsoft Jan 31, 2025
b6c59ae
uv fixes
rickyloynd-microsoft Jan 31, 2025
bef7e5d
uv fixes
rickyloynd-microsoft Feb 1, 2025
1fb5ee4
uv fixes
rickyloynd-microsoft Feb 1, 2025
1d7f4eb
uv fixes
rickyloynd-microsoft Feb 1, 2025
516e689
uv fixes
rickyloynd-microsoft Feb 1, 2025
ffe719a
uv fixes
rickyloynd-microsoft Feb 1, 2025
ba14e78
uv fixes
rickyloynd-microsoft Feb 3, 2025
2eb817e
uv fixes
rickyloynd-microsoft Feb 3, 2025
95b1276
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 3, 2025
6633169
uv fixes
rickyloynd-microsoft Feb 4, 2025
880df13
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 4, 2025
b4ea0ce
uv fixes
rickyloynd-microsoft Feb 5, 2025
53da266
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 5, 2025
6a04851
Add line to autogenstudio section of uv.lock
rickyloynd-microsoft Feb 5, 2025
ad514eb
poe check fixes
rickyloynd-microsoft Feb 5, 2025
18ae4dc
uv
rickyloynd-microsoft Feb 5, 2025
7be995d
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 5, 2025
0e01720
hash output for detecting log changes
rickyloynd-microsoft Feb 6, 2025
0416e8d
Merge branch 'main' of github.com:microsoft/autogen
rickyloynd-microsoft Feb 6, 2025
0298591
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 6, 2025
0bc0500
Make logger and config args optional
rickyloynd-microsoft Feb 7, 2025
66029cf
terminology: settings -> configs
rickyloynd-microsoft Feb 7, 2025
d9ad986
Merge branch 'main' of github.com:microsoft/autogen
rickyloynd-microsoft Feb 7, 2025
2b2cbdb
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 7, 2025
566709b
Simplify the API in preparation for Webby
rickyloynd-microsoft Feb 11, 2025
2ef5e4a
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 11, 2025
9e7d245
uv.lock
rickyloynd-microsoft Feb 11, 2025
1ce4cd9
Restore version for autogenstudio
rickyloynd-microsoft Feb 11, 2025
494d81e
Add a retrieval sample, which accesses the memory controller directly…
rickyloynd-microsoft Feb 12, 2025
54b0faa
Change of terminology: Agentic Memory -> Task-Centric Memory
rickyloynd-microsoft Feb 12, 2025
0b9f042
Move support files into utils subdir.
rickyloynd-microsoft Feb 12, 2025
a720863
Update readme files per reviewer feedback.
rickyloynd-microsoft Feb 14, 2025
b0e72a7
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 14, 2025
dba5b55
Get API Reference documentation to build correctly.
rickyloynd-microsoft Feb 15, 2025
01d8b9d
Add code example provided by @ekzhu
rickyloynd-microsoft Feb 15, 2025
193466b
Added installation instructions and a code snippet to the docstring.
rickyloynd-microsoft Feb 15, 2025
39d460a
Code format fix in the docstring
rickyloynd-microsoft Feb 15, 2025
8f9d066
Use TypedDicts in the nested-config pattern to minimize code changes …
rickyloynd-microsoft Feb 17, 2025
94eab06
Merge branch 'refs/heads/main' into agentic_memory
rickyloynd-microsoft Feb 17, 2025
f892c18
Add clarifying diagrams.
rickyloynd-microsoft Feb 18, 2025
a15bfd1
fix image sizes
rickyloynd-microsoft Feb 18, 2025
3ea8011
Merge branch 'main' into agentic_memory
rickyloynd-microsoft Feb 19, 2025
58ecd7e
Add file docstrings to sample code.
rickyloynd-microsoft Feb 20, 2025
00e27e1
Merge branch 'agentic_memory' of github.com:microsoft/autogen into ag…
rickyloynd-microsoft Feb 20, 2025
4466eee
uv sync --all-extras
rickyloynd-microsoft Feb 20, 2025
64dc3c0
restore previous uv.lock
rickyloynd-microsoft Feb 20, 2025
e15d0eb
changes for webby
rickyloynd-microsoft Feb 21, 2025
af362f6
experimental
rickyloynd-microsoft Feb 21, 2025
4d6c9f4
docs
rickyloynd-microsoft Feb 23, 2025
261fe6f
Add Teachability(Memory)
rickyloynd-microsoft Feb 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/

.ruff_cache/

Expand Down
2 changes: 2 additions & 0 deletions python/packages/autogen-core/docs/src/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ python/autogen_ext.models.openai
python/autogen_ext.models.replay
python/autogen_ext.models.azure
python/autogen_ext.models.semantic_kernel
python/autogen_ext.task_centric_memory
python/autogen_ext.task_centric_memory.utils
python/autogen_ext.models.ollama
python/autogen_ext.tools.code_execution
python/autogen_ext.tools.graphrag
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.task\_centric\_memory
==================================


.. automodule:: autogen_ext.task_centric_memory
:members:
:undoc-members:
:show-inheritance:
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.task\_centric\_memory.utils
========================================


.. automodule:: autogen_ext.task_centric_memory.utils
:members:
:undoc-members:
:show-inheritance:
3 changes: 3 additions & 0 deletions python/packages/autogen-ext/imgs/task_centric_memory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions python/packages/autogen-ext/imgs/task_centric_memory_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions python/packages/autogen-ext/imgs/task_centric_memory_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion python/packages/autogen-ext/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ jupyter-executor = [
"nbclient>=0.10.2",
]

task-centric-memory = ["chromadb>=0.6.3"]

semantic-kernel-core = [
"semantic-kernel>=1.17.1",
]
Expand Down Expand Up @@ -140,7 +142,7 @@ dev = [
[tool.ruff]
extend = "../../pyproject.toml"
include = ["src/**", "tests/*.py"]
exclude = ["src/autogen_ext/agents/web_surfer/*.js", "src/autogen_ext/runtimes/grpc/protos", "tests/protos"]
exclude = ["src/autogen_ext/agents/web_surfer/*.js", "src/autogen_ext/runtimes/grpc/protos", "tests/protos", "README.md"]

[tool.pyright]
extends = "../../pyproject.toml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Task-Centric Memory

**Task-Centric Memory** is an active research project aimed at giving AI agents the ability to:

* Accomplish general tasks more effectively by learning quickly and continually beyond context-window limitations.
* Remember guidance, corrections, plans, and demonstrations provided by users.
* Learn through the agent's own experience and adapt quickly to changing circumstances.
* Avoid repeating mistakes on tasks that are similar to those previously encountered.

## Installation

Install AutoGen and its extension package as follows:

```bash
pip install -U "autogen-agentchat" "autogen-ext[openai]" "autogen-ext[task-centric-memory]"
```

## Quickstart

<p align="right">
<img src="../../../imgs/task_centric_memory_2.png" alt="Description" width="150" align="right" style="margin-left: 10px;">
</p>

This first code snippet runs a basic test to verify that the installation was successful,
as illustrated by the diagram to the right.

```python
import asyncio
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.task_centric_memory import TaskCentricMemoryController
from autogen_ext.task_centric_memory.utils import PageLogger


async def main() -> None:
client = OpenAIChatCompletionClient(model="gpt-4o")
page_logger = PageLogger(config={"level": "DEBUG", "path": "~/pagelogs/quickstart"}) # Optional, but very useful.
memory_controller = TaskCentricMemoryController(reset=True, client=client, logger=page_logger)

# Add a few task-insight pairs as memories, where an insight can be any string that may help solve the task.
await memory_controller.add_memo(task="What color do I like?", insight="Deep blue is my favorite color")
await memory_controller.add_memo(task="What's another color I like?", insight="I really like cyan")
await memory_controller.add_memo(task="What's my favorite food?", insight="Halibut is my favorite")

# Retrieve memories for a new task that's related to only two of the stored memories.
memos = await memory_controller.retrieve_relevant_memos(task="What colors do I like most?")
print("{} memories retrieved".format(len(memos)))
for memo in memos:
print("- " + memo.insight)

asyncio.run(main())
```
Copy link
Collaborator

@ekzhu ekzhu Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another example perhaps like this. It can be just another code block in this file for now. In a future PR when we write a user guide for this memory module, we can move this example to the user guide.

import asyncio
from dataclasses import dataclass
from typing import List

from autogen_core import AgentId, MessageContext, RoutedAgent, SingleThreadedAgentRuntime, message_handler
from autogen_core.models import ChatCompletionClient, LLMMessage, SystemMessage, UserMessage
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.task_centric_memory import PageLogger, TaskCentricMemoryController


@dataclass
class Message:
    content: str


class MemoryEnabledAgent(RoutedAgent):
    def __init__(
        self, description: str, model_client: ChatCompletionClient, task_memory_controller: TaskCentricMemoryController
    ) -> None:
        super().__init__(description)
        self._model_client = model_client
        self._task_memory_controller = task_memory_controller

    @message_handler
    async def handle_message(self, message: Message, context: MessageContext) -> Message:
        # Retrieve relevant memories for the task.
        memos = await self._task_memory_controller.retrieve_relevant_memos(task=message.content)
        # Format the memories for the model.
        formatted_memos = "Relevant context about the user: \n\n" + "\n".join([memo.insight for memo in memos])
        print(f"{'-'*38}Memos{'-'*38}:\n{formatted_memos}\n{'-'*80}")
        # Create the messages for the model with the retrieved memories.
        messages: List[LLMMessage] = [
            SystemMessage(content="You are a helpful assistant."),
            UserMessage(content=formatted_memos, source="user"),
            UserMessage(content=message.content, source="user"),
        ]
        # Call the model with the messages.
        model_result = await self._model_client.create(messages=messages)
        assert isinstance(model_result.content, str)
        # Send the model's response to the user.
        return Message(content=model_result.content)


async def main() -> None:
    client = OpenAIChatCompletionClient(model="gpt-4o")
    page_logger = PageLogger(config={"level": "DEBUG", "path": "~/pagelogs/quickstart"})  # Optional, but very useful.
    memory_controller = TaskCentricMemoryController(reset=True, client=client, logger=page_logger)

    # Add a few task-insight pairs as memories, where an insight can be any string that may help solve the task.
    await memory_controller.add_memo(task="What color do I like?", insight="Deep blue is my favorite color")
    await memory_controller.add_memo(task="What's another color I like?", insight="I really like cyan")
    await memory_controller.add_memo(task="What's my favorite food?", insight="Halibut is my favorite")

    # Create an agent runtime.
    runtime = SingleThreadedAgentRuntime()

    # Start the agent runtime.
    runtime.start()

    # Register the agent type.
    await MemoryEnabledAgent.register(
        runtime,
        "memory_enabled_agent",
        lambda: MemoryEnabledAgent(
            "A agent with memory", model_client=client, task_memory_controller=memory_controller
        ),
    )

    # Send a direct message to the agent.
    response = await runtime.send_message(
        Message(content="What colors do I like most"), AgentId("memory_enabled_agent", "default")
    )

    print("Agent response: " + response.content)

    # Stop the agent runtime.
    await runtime.stop()


asyncio.run(main())
--------------------------------------Memos--------------------------------------:
Relevant context about the user: 

Deep blue is my favorite color
I really like cyan
--------------------------------------------------------------------------------
Agent response: Based on the information you've provided, you really like deep blue and cyan.

To show how to use this as part of an agent implementation in the Core API.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@victordibia could you comment how can we perhaps leverage this module as an implementation of the autogen_core.memory.Memory interface?

Not for this PR but for future one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.
It seems to me that the example above could be indeed implemented (to some extent) using the Memory interface.

  • add maps to memory_controller.add_memo
  • and update_context maps to formatted_memos = ...

Copy link
Collaborator

@ekzhu ekzhu Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I do think using the controller we can implement the autogen_core.memory.Memory interface. I can give it a try.

If that's the case we should move this module to autogen_ext.memory.task_centric_memory.

Copy link
Contributor Author

@rickyloynd-microsoft rickyloynd-microsoft Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without losing any of the current functionality of TaskCentricMemoryController? Like learning from its own experience?? (That's TaskCentricMemoryController.train_on_task(self, task: str, expected_answer: str), which requires the expected answer.)

TaskCentricMemoryController is still active research so the interface is highly likely to change, as we discussed before. Why do you now want it in Core?

Copy link
Collaborator

@ekzhu ekzhu Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you now want it in Core?

We are not moving it to core. It's staying in extension. My message earlier refers to autogen_ext module.

I am just trying to play with it and see what it takes me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New code example from @ekzhu added to the README.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I do think using the controller we can implement the autogen_core.memory.Memory interface. I can give it a try.

If that's the case we should move this module to autogen_ext.memory.task_centric_memory.

@ekzhu, should we wait for the results of your attempt to use TaskCentricMemoryController to implement the autogen_core.memory.Memory interface before we try to clarify the relations and connections between TaskCentricMemory and the autogen_core.memory.Memory interface?


<p align="right">
<img src="../../../imgs/task_centric_memory_3.png" alt="Description" width="150" align="right" style="margin-left: 10px;">
</p>

This second code example shows one way to incorporate task-centric memory directly into an AutoGen agent,
in this case a subclass of RoutedAgent.
To keep the code smalle, only the simplest form of memory retrieval is exercised by this agent.

```python

import asyncio
from dataclasses import dataclass
from typing import List

from autogen_core import AgentId, MessageContext, RoutedAgent, SingleThreadedAgentRuntime, message_handler
from autogen_core.models import ChatCompletionClient, LLMMessage, SystemMessage, UserMessage
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.task_centric_memory import TaskCentricMemoryController
from autogen_ext.task_centric_memory.utils import PageLogger


@dataclass
class Message:
content: str


class MemoryEnabledAgent(RoutedAgent):
def __init__(
self, description: str, model_client: ChatCompletionClient, memory_controller: TaskCentricMemoryController
) -> None:
super().__init__(description)
self._model_client = model_client
self._memory_controller = memory_controller

@message_handler
async def handle_message(self, message: Message, context: MessageContext) -> Message:
# Retrieve relevant memories for the task.
memos = await self._memory_controller.retrieve_relevant_memos(task=message.content)

# Format the memories for the model.
formatted_memos = "Info that may be useful:\n" + "\n".join(["- " + memo.insight for memo in memos])
print(f"{'-'*23}Text appended to the user message{'-'*24}\n{formatted_memos}\n{'-'*80}")

# Create the messages for the model with the retrieved memories.
messages: List[LLMMessage] = [
SystemMessage(content="You are a helpful assistant."),
UserMessage(content=message.content, source="user"),
UserMessage(content=formatted_memos, source="user"),
]

# Call the model with the messages.
model_result = await self._model_client.create(messages=messages)
assert isinstance(model_result.content, str)

# Send the model's response to the user.
return Message(content=model_result.content)


async def main() -> None:
client = OpenAIChatCompletionClient(model="gpt-4o")
page_logger = PageLogger(config={"level": "DEBUG", "path": "~/pagelogs/quickstart2"}) # Optional, but very useful.
memory_controller = TaskCentricMemoryController(reset=True, client=client, logger=page_logger)

# Prepopulate memory to mimic learning from a prior session.
await memory_controller.add_memo(task="What color do I like?", insight="Deep blue is my favorite color")
await memory_controller.add_memo(task="What's another color I like?", insight="I really like cyan")
await memory_controller.add_memo(task="What's my favorite food?", insight="Halibut is my favorite")

# Create and start an agent runtime.
runtime = SingleThreadedAgentRuntime()
runtime.start()

# Register the agent type.
await MemoryEnabledAgent.register(
runtime,
"memory_enabled_agent",
lambda: MemoryEnabledAgent(
"A agent with memory", model_client=client, memory_controller=memory_controller
),
)

# Send a direct message to the agent.
request = "What colors do I like most?"
print("User request: " + request)
response = await runtime.send_message(
Message(content=request), AgentId("memory_enabled_agent", "default")
)
print("Agent response: " + response.content)

# Stop the agent runtime.
await runtime.stop()


asyncio.run(main())
```

## Sample Code

The example above modifies the agent's code.
But it's also possible to add task-centric memory to an agent or multi-agent team _without_ modifying any agent code.
See the [sample code](../../../../../samples/task_centric_memory) for that and other forms of fast, memory-based learning.


## Architecture

<p align="right">
<img src="../../../imgs/task_centric_memory.png" alt="Description" width="300" align="right" style="margin-left: 10px;">
</p>

The block diagram to the right outlines the key components of the architecture in the most general form.
The memory components are shown in blue, and the green blocks represent external components.

The **Task-Centric Memory Controller** implements the fast-learning methods described below,
and manages communication with a **Task-Centric Memory Bank** containing a vector DB and associated structures.

The **Agent or Team** is the AI agent or team of agents to which memory is being added.
The sample code shows how to add task-centric memory to a simple AssistantAgent or a MagenticOneGroupChat team.

The **Apprentice, app, or service** represents the code that instantiates the agent and memory controller,
and routes information between them, effectively wrapping agent and memory into a combined component.
The term _Apprentice_ connotes that this combination uses memory to learn quickly on the job.
The Apprentice class is a minimal reference implementation provided as utility code for illustration and testing,
but most applications will use their own code instead of the Apprentice.

## Memory Creation and Storage

Each stored memory (called a _memo_) contains a text insight and (optionally) a task description.
The insight is intended to help the agent accomplish future tasks that are similar to a prior task.
The memory controller provides methods for different types of learning.
If the user provides advice for solving a given task, the advice is extracted and stored as an insight.
If the user demonstrates how to perform a task,
the task and demonstration are stored together as an insight used to solve similar but different tasks.
If the agent is given a task (free of side-effects) and some means of determining success or failure,
the memory controller repeats the following learning loop in the background some number of times:

1. Test the agent on the task a few times to check for a failure.
2. If a failure is found, analyze the agent's response in order to:
1. Diagnose the failure of reasoning or missing information,
2. Phrase a general piece of advice, such as what a teacher might give to a student,
3. Temporarily append this advice to the task description,
4. Return to step 1.
5. If some piece of advice succeeds in helping the agent solve the task a number of times, add the advice as an insight to memory.
3. For each insight to be stored in memory, an LLM is prompted to generate a set of free-form, multi-word topics related to the insight. Each topic is embedded to a fixed-length vector and stored in a vector DB mapping it to the topic’s related insight.

## Memory Retrieval and Usage

The memory controller provides methods for different types of memory retrieval.
When the agent is given a task, the following steps are performed by the controller:
1. The task is rephrased into a generalized form.
2. A set of free-form, multi-word query topics are generated from the generalized task.
3. A potentially large number of previously stored topics, those most similar to each query topic, are retrieved from the vector DB along with the insights they map to.
4. These candidate memos are filtered by the aggregate similarity of their stored topics to the query topics.
5. In the final filtering stage, an LLM is prompted to validate only those insights that seem potentially useful in solving the task at hand.

Retrieved insights that pass the filtering steps are listed under a heading like
"Important insights that may help solve tasks like this", then appended to the task description before it is passed to the agent as usual.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .task_centric_memory_controller import TaskCentricMemoryController

Check warning on line 1 in python/packages/autogen-ext/src/autogen_ext/task_centric_memory/__init__.py

View check run for this annotation

Codecov / codecov/patch

python/packages/autogen-ext/src/autogen_ext/task_centric_memory/__init__.py#L1

Added line #L1 was not covered by tests

__all__ = ["TaskCentricMemoryController"]

Check warning on line 3 in python/packages/autogen-ext/src/autogen_ext/task_centric_memory/__init__.py

View check run for this annotation

Codecov / codecov/patch

python/packages/autogen-ext/src/autogen_ext/task_centric_memory/__init__.py#L3

Added line #L3 was not covered by tests
Loading
Loading