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

Add ChatCompletionCache along with AbstractStore for caching completions #4924

Merged
merged 6 commits into from
Jan 16, 2025
Merged
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
Make cache store typed, and improve docs
srjoglekar246 committed Jan 16, 2025
commit 75729640b998169612a9d5f05c2242dbfc2c9d7f
2 changes: 1 addition & 1 deletion python/packages/autogen-agentchat/tests/test_group_chat.py
Original file line number Diff line number Diff line change
@@ -34,10 +34,10 @@
from autogen_agentchat.teams._group_chat._swarm_group_chat import SwarmGroupChatManager
from autogen_agentchat.ui import Console
from autogen_core import AgentId, CancellationToken
from autogen_core.models import ReplayChatCompletionClient
from autogen_core.tools import FunctionTool
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.replay import ReplayChatCompletionClient
from openai.resources.chat.completions import AsyncCompletions
from openai.types.chat.chat_completion import ChatCompletion, Choice
from openai.types.chat.chat_completion_chunk import ChatCompletionChunk
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
)
from autogen_agentchat.teams._group_chat._magentic_one._magentic_one_orchestrator import MagenticOneOrchestrator
from autogen_core import AgentId, CancellationToken
from autogen_core.models import ReplayChatCompletionClient
from autogen_ext.models.replay import ReplayChatCompletionClient
from utils import FileLogHandler

logger = logging.getLogger(EVENT_LOGGER_NAME)
4 changes: 4 additions & 0 deletions python/packages/autogen-core/docs/src/reference/index.md
Original file line number Diff line number Diff line change
@@ -48,12 +48,16 @@ python/autogen_ext.agents.video_surfer
python/autogen_ext.agents.video_surfer.tools
python/autogen_ext.auth.azure
python/autogen_ext.teams.magentic_one
python/autogen_ext.models.cache
python/autogen_ext.models.openai
python/autogen_ext.models.replay
python/autogen_ext.tools.langchain
python/autogen_ext.tools.graphrag
python/autogen_ext.tools.code_execution
python/autogen_ext.code_executors.local
python/autogen_ext.code_executors.docker
python/autogen_ext.code_executors.azure
python/autogen_ext.cache_store.diskcache
python/autogen_ext.cache_store.redis
python/autogen_ext.runtimes.grpc
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.cache_store.diskcache
==================================


.. automodule:: autogen_ext.cache_store.diskcache
:members:
:undoc-members:
:show-inheritance:
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.cache_store.redis
==============================


.. automodule:: autogen_ext.cache_store.redis
:members:
:undoc-members:
:show-inheritance:
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.models.cache
=========================


.. automodule:: autogen_ext.models.cache
:members:
:undoc-members:
:show-inheritance:
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
autogen\_ext.models.replay
==========================


.. automodule:: autogen_ext.models.replay
:members:
:undoc-members:
:show-inheritance:
Original file line number Diff line number Diff line change
@@ -8,7 +8,9 @@
"\n",
"In many cases, agents need access to LLM model services such as OpenAI, Azure OpenAI, or local models. Since there are many different providers with different APIs, `autogen-core` implements a protocol for [model clients](../../core-user-guide/framework/model-clients.ipynb) and `autogen-ext` implements a set of model clients for popular model services. AgentChat can use these model clients to interact with model services. \n",
"\n",
"**NOTE:** See {py:class}`~autogen_core.models.ChatCompletionCache` for a caching wrapper to use with the following clients."
"```{note}\n",
"See {py:class}`~autogen_ext.models.cache.ChatCompletionCache` for a caching wrapper to use with the following clients.\n",
"```"
]
},
{
Original file line number Diff line number Diff line change
@@ -327,9 +327,20 @@
"source": [
"## Caching Wrapper\n",
"\n",
"`autogen_core` implements a {py:class}`~autogen_core.models.ChatCompletionCache` that can wrap any {py:class}`~autogen_core.models.ChatCompletionClient`. Using this wrapper avoids incurring token usage when querying the underlying client with the same prompt multiple times. \n",
"`autogen_ext` implements {py:class}`~autogen_ext.models.cache.ChatCompletionCache` that can wrap any {py:class}`~autogen_core.models.ChatCompletionClient`. Using this wrapper avoids incurring token usage when querying the underlying client with the same prompt multiple times.\n",
"\n",
"{py:class}`~autogen_core.models.ChatCompletionCache` uses a {py:class}`~autogen_core.CacheStore` protocol to allow duck-typing any storage object that has a pair of `get` & `set` methods (such as `redis.Redis` or `diskcache.Cache`). Here's an example of using `diskcache` for local caching:"
"{py:class}`~autogen_core.models.ChatCompletionCache` uses a {py:class}`~autogen_core.CacheStore` protocol. We have implemented some useful variants of {py:class}`~autogen_core.CacheStore` including {py:class}`~autogen_ext.cache_store.diskcache.DiskCacheStore` and {py:class}`~autogen_ext.cache_store.redis.RedisStore`.\n",
"\n",
"Here's an example of using `diskcache` for local caching:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# pip install -U \"autogen-ext[openai, diskcache]\""
]
},
{
@@ -346,18 +357,37 @@
}
],
"source": [
"from typing import Any, Dict, Optional\n",
"import asyncio\n",
"import tempfile\n",
"\n",
"from autogen_core.models import ChatCompletionCache\n",
"from autogen_core.models import UserMessage\n",
"from autogen_ext.cache_store.diskcache import DiskCacheStore\n",
"from autogen_ext.models.cache import CHAT_CACHE_VALUE_TYPE, ChatCompletionCache\n",
"from autogen_ext.models.openai import OpenAIChatCompletionClient\n",
"from diskcache import Cache\n",
"\n",
"diskcache_client = Cache(\"/tmp/diskcache\")\n",
"\n",
"cached_client = ChatCompletionCache(model_client, diskcache_client)\n",
"response = await cached_client.create(messages=messages)\n",
"async def main() -> None:\n",
" with tempfile.TemporaryDirectory() as tmpdirname:\n",
" # Initialize the original client\n",
" openai_model_client = OpenAIChatCompletionClient(model=\"gpt-4o\")\n",
"\n",
" # Then initialize the CacheStore, in this case with diskcache.Cache.\n",
" # You can also use redis like:\n",
" # from autogen_ext.cache_store.redis import RedisStore\n",
" # import redis\n",
" # redis_instance = redis.Redis()\n",
" # cache_store = RedisCacheStore[CHAT_CACHE_VALUE_TYPE](redis_instance)\n",
" cache_store = DiskCacheStore[CHAT_CACHE_VALUE_TYPE](Cache(tmpdirname))\n",
" cache_client = ChatCompletionCache(openai_model_client, cache_store)\n",
"\n",
" response = await cache_client.create([UserMessage(content=\"Hello, how are you?\", source=\"user\")])\n",
" print(response) # Should print response from OpenAI\n",
" response = await cache_client.create([UserMessage(content=\"Hello, how are you?\", source=\"user\")])\n",
" print(response) # Should print cached response\n",
"\n",
"\n",
"cached_response = await cached_client.create(messages=messages)\n",
"print(cached_response.cached)"
"asyncio.run(main())"
]
},
{
3 changes: 2 additions & 1 deletion python/packages/autogen-core/src/autogen_core/__init__.py
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
from ._agent_runtime import AgentRuntime
from ._agent_type import AgentType
from ._base_agent import BaseAgent
from ._cache_store import CacheStore
from ._cache_store import CacheStore, InMemoryStore
from ._cancellation_token import CancellationToken
from ._closure_agent import ClosureAgent, ClosureContext
from ._component_config import (
@@ -87,6 +87,7 @@
"AgentRuntime",
"BaseAgent",
"CacheStore",
"InMemoryStore",
"CancellationToken",
"AgentInstantiationContext",
"TopicId",
24 changes: 18 additions & 6 deletions python/packages/autogen-core/src/autogen_core/_cache_store.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
from typing import Any, Optional, Protocol
from typing import Any, Dict, Generic, Optional, Protocol, TypeVar, cast

T = TypeVar("T")

class CacheStore(Protocol):

class CacheStore(Protocol, Generic[T]):
"""
This protocol defines the basic interface for store/cache operations.
Allows duck-typing with any object that implements the get and set methods,
such as redis or diskcache interfaces.
Sub-classes should handle the lifecycle of underlying storage.
"""

def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
"""
Retrieve an item from the store.
@@ -23,7 +24,7 @@ def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
"""
...

def set(self, key: str, value: Any) -> Optional[Any]:
def set(self, key: str, value: T) -> None:
"""
Set an item in the store.
@@ -32,3 +33,14 @@ def set(self, key: str, value: Any) -> Optional[Any]:
value: The value to be stored in the store.
"""
...


class InMemoryStore(CacheStore[T]):
def __init__(self) -> None:
self.store: Dict[str, Any] = {}

def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
return cast(Optional[T], self.store.get(key, default))

def set(self, key: str, value: T) -> None:
self.store[key] = value
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from ._cache import ChatCompletionCache
from ._model_client import ChatCompletionClient, ModelCapabilities, ModelFamily, ModelInfo # type: ignore
from ._replay_chat_completion_client import ReplayChatCompletionClient
from ._types import (
AssistantMessage,
ChatCompletionTokenLogprob,
@@ -17,7 +15,6 @@

__all__ = [
"ModelCapabilities",
"ChatCompletionCache",
"ChatCompletionClient",
"SystemMessage",
"UserMessage",
@@ -32,5 +29,4 @@
"ChatCompletionTokenLogprob",
"ModelFamily",
"ModelInfo",
"ReplayChatCompletionClient",
]
18 changes: 17 additions & 1 deletion python/packages/autogen-core/tests/test_cache_store.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unittest.mock import Mock

from autogen_core import CacheStore
from autogen_core import CacheStore, InMemoryStore


def test_set_and_get_object_key_value() -> None:
@@ -30,3 +30,19 @@ def test_set_overwrite_existing_key() -> None:
mock_store.get.return_value = new_value
mock_store.set.assert_called_with(key, new_value)
assert mock_store.get(key) == new_value


def test_inmemory_store() -> None:
store = InMemoryStore[int]()
test_key = "test_key"
test_value = 42
store.set(test_key, test_value)
assert store.get(test_key) == test_value

new_value = 2
store.set(test_key, new_value)
assert store.get(test_key) == new_value

key = "non_existent_key"
default_value = 99
assert store.get(key, default_value) == default_value
6 changes: 6 additions & 0 deletions python/packages/autogen-ext/pyproject.toml
Original file line number Diff line number Diff line change
@@ -46,6 +46,12 @@ video-surfer = [
"ffmpeg-python",
"openai-whisper",
]
diskcache = [
"diskcache>=5.6.3"
]
redis = [
"redis>=5.2.1"
]

grpc = [
"grpcio~=1.62.0", # TODO: update this once we have a stable version.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Any, Optional, TypeVar, cast

import diskcache
from autogen_core import CacheStore

T = TypeVar("T")


class DiskCacheStore(CacheStore[T]):
"""
A typed CacheStore implementation that uses diskcache as the underlying storage.
See :class:`~autogen_ext.models.cache.ChatCompletionCache` for an example of usage.
Args:
cache_instance: An instance of diskcache.Cache.
The user is responsible for managing the DiskCache instance's lifetime.
"""

def __init__(self, cache_instance: diskcache.Cache): # type: ignore[no-any-unimported]
self.cache = cache_instance

def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
return cast(Optional[T], self.cache.get(key, default)) # type: ignore[reportUnknownMemberType]

def set(self, key: str, value: T) -> None:
self.cache.set(key, cast(Any, value)) # type: ignore[reportUnknownMemberType]
29 changes: 29 additions & 0 deletions python/packages/autogen-ext/src/autogen_ext/cache_store/redis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Any, Optional, TypeVar, cast

import redis
from autogen_core import CacheStore

T = TypeVar("T")


class RedisStore(CacheStore[T]):
"""
A typed CacheStore implementation that uses redis as the underlying storage.
See :class:`~autogen_ext.models.cache.ChatCompletionCache` for an example of usage.
Args:
cache_instance: An instance of `redis.Redis`.
The user is responsible for managing the Redis instance's lifetime.
"""

def __init__(self, redis_instance: redis.Redis):
self.cache = redis_instance

def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
value = cast(Optional[T], self.cache.get(key))
if value is None:
return default
return value

def set(self, key: str, value: T) -> None:
self.cache.set(key, cast(Any, value))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from ._chat_completion_cache import CHAT_CACHE_VALUE_TYPE, ChatCompletionCache

__all__ = [
"CHAT_CACHE_VALUE_TYPE",
"ChatCompletionCache",
]
Original file line number Diff line number Diff line change
@@ -3,74 +3,80 @@
import warnings
from typing import Any, AsyncGenerator, List, Mapping, Optional, Sequence, Union, cast

from .._cache_store import CacheStore
from .._cancellation_token import CancellationToken
from ..tools import Tool, ToolSchema
from ._model_client import (
from autogen_core import CacheStore, CancellationToken
from autogen_core.models import (
ChatCompletionClient,
ModelCapabilities, # type: ignore
ModelInfo,
)
from ._types import (
CreateResult,
LLMMessage,
ModelCapabilities, # type: ignore
ModelInfo,
RequestUsage,
)
from autogen_core.tools import Tool, ToolSchema

CHAT_CACHE_VALUE_TYPE = Union[CreateResult, List[Union[str, CreateResult]]]


class ChatCompletionCache(ChatCompletionClient):
"""
A wrapper around a ChatCompletionClient that caches creation results from an underlying client.
A wrapper around a :class:`~autogen_ext.models.cache.ChatCompletionClient` that caches
creation results from an underlying client.
Cache hits do not contribute to token usage of the original client.
Typical Usage:
Lets use caching with `openai` as an example:
Lets use caching on disk with `openai` client as an example.
First install `autogen-ext` with the required packages:
.. code-block:: bash
.. code-block:: bash
pip install "autogen-ext[openai]==0.4.0.dev13"
pip install -U "autogen-ext[openai, diskcache]"
And use it as:
And use it as:
.. code-block:: python
.. code-block:: python
# Initialize the original client
from autogen_ext.models.openai import OpenAIChatCompletionClient
import asyncio
import tempfile
openai_client = OpenAIChatCompletionClient(
model="gpt-4o-2024-08-06",
# api_key="sk-...", # Optional if you have an OPENAI_API_KEY environment variable set.
)
from autogen_core.models import UserMessage
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.cache import ChatCompletionCache, CHAT_CACHE_VALUE_TYPE
from autogen_ext.cache_store.diskcache import DiskCacheStore
from diskcache import Cache
# Then initialize the CacheStore. Either a Redis store:
import redis
redis_client = redis.Redis(host="localhost", port=6379, db=0)
async def main():
with tempfile.TemporaryDirectory() as tmpdirname:
# Initialize the original client
openai_model_client = OpenAIChatCompletionClient(model="gpt-4o")
# or diskcache:
from diskcache import Cache
# Then initialize the CacheStore, in this case with diskcache.Cache.
# You can also use redis like:
# from autogen_ext.cache_store.redis import RedisStore
# import redis
# redis_instance = redis.Redis()
# cache_store = RedisCacheStore[CHAT_CACHE_VALUE_TYPE](redis_instance)
cache_store = DiskCacheStore[CHAT_CACHE_VALUE_TYPE](Cache(tmpdirname))
cache_client = ChatCompletionCache(openai_model_client, cache_store)
diskcache_client = Cache("/tmp/diskcache")
response = await cache_client.create([UserMessage(content="Hello, how are you?", source="user")])
print(response) # Should print response from OpenAI
response = await cache_client.create([UserMessage(content="Hello, how are you?", source="user")])
print(response) # Should print cached response
# Then initialize the ChatCompletionCache with the store:
from autogen_core.models import ChatCompletionCache
# Cached client
cached_client = ChatCompletionCache(openai_client, diskcache_client)
asyncio.run(main())
You can now use the `cached_client` as you would the original client, but with caching enabled.
"""
You can now use the `cached_client` as you would the original client, but with caching enabled.
def __init__(self, client: ChatCompletionClient, store: CacheStore):
"""
Initialize a new ChatCompletionCache.
Args:
client (ChatCompletionClient): The original ChatCompletionClient to wrap.
store (CacheStore): A store object that implements get and set methods.
The user is responsible for managing the store's lifecycle & clearing it (if needed).
"""

Args:
client (ChatCompletionClient): The original ChatCompletionClient to wrap.
store (CacheStore): A store object that implements get and set methods.
The user is responsible for managing the store's lifecycle & clearing it (if needed).
"""
def __init__(self, client: ChatCompletionClient, store: CacheStore[CHAT_CACHE_VALUE_TYPE]):
self.client = client
self.store = store

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from ._replay_chat_completion_client import ReplayChatCompletionClient

__all__ = [
"ReplayChatCompletionClient",
]
Original file line number Diff line number Diff line change
@@ -4,20 +4,17 @@
import warnings
from typing import Any, AsyncGenerator, List, Mapping, Optional, Sequence, Union

from .. import EVENT_LOGGER_NAME
from .._cancellation_token import CancellationToken
from ..tools import Tool, ToolSchema
from ._model_client import (
from autogen_core import EVENT_LOGGER_NAME, CancellationToken
from autogen_core.models import (
ChatCompletionClient,
CreateResult,
LLMMessage,
ModelCapabilities, # type: ignore
ModelFamily,
ModelInfo,
)
from ._types import (
CreateResult,
LLMMessage,
RequestUsage,
)
from autogen_core.tools import Tool, ToolSchema

logger = logging.getLogger(EVENT_LOGGER_NAME)

@@ -43,7 +40,8 @@ class ReplayChatCompletionClient(ChatCompletionClient):
.. code-block:: python
from autogen_core.models import ReplayChatCompletionClient, UserMessage
from autogen_core.models import UserMessage
from autogen_ext.models.replay import ReplayChatCompletionClient
async def example():
@@ -62,7 +60,8 @@ async def example():
.. code-block:: python
import asyncio
from autogen_core.models import ReplayChatCompletionClient, UserMessage
from autogen_core.models import UserMessage
from autogen_ext.models.replay import ReplayChatCompletionClient
async def example():
@@ -87,7 +86,8 @@ async def example():
.. code-block:: python
import asyncio
from autogen_core.models import ReplayChatCompletionClient, UserMessage
from autogen_core.models import UserMessage
from autogen_ext.models.replay import ReplayChatCompletionClient
async def example():
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import tempfile

import pytest

diskcache = pytest.importorskip("diskcache")


def test_diskcache_store_basic() -> None:
from autogen_ext.cache_store.diskcache import DiskCacheStore
from diskcache import Cache

with tempfile.TemporaryDirectory() as temp_dir:
cache = Cache(temp_dir)
store = DiskCacheStore[int](cache)
test_key = "test_key"
test_value = 42
store.set(test_key, test_value)
assert store.get(test_key) == test_value

new_value = 2
store.set(test_key, new_value)
assert store.get(test_key) == new_value

key = "non_existent_key"
default_value = 99
assert store.get(key, default_value) == default_value


def test_diskcache_with_different_instances() -> None:
from autogen_ext.cache_store.diskcache import DiskCacheStore
from diskcache import Cache

with tempfile.TemporaryDirectory() as temp_dir_1, tempfile.TemporaryDirectory() as temp_dir_2:
cache_1 = Cache(temp_dir_1)
cache_2 = Cache(temp_dir_2)

store_1 = DiskCacheStore[int](cache_1)
store_2 = DiskCacheStore[int](cache_2)

test_key = "test_key"
test_value_1 = 5
test_value_2 = 6

store_1.set(test_key, test_value_1)
assert store_1.get(test_key) == test_value_1

store_2.set(test_key, test_value_2)
assert store_2.get(test_key) == test_value_2
53 changes: 53 additions & 0 deletions python/packages/autogen-ext/tests/cache_store/test_redis_store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from unittest.mock import MagicMock

import pytest

redis = pytest.importorskip("redis")


def test_redis_store_basic() -> None:
from autogen_ext.cache_store.redis import RedisStore

redis_instance = MagicMock()
store = RedisStore[int](redis_instance)
test_key = "test_key"
test_value = 42
store.set(test_key, test_value)
redis_instance.set.assert_called_with(test_key, test_value)
redis_instance.get.return_value = test_value
assert store.get(test_key) == test_value

new_value = 2
store.set(test_key, new_value)
redis_instance.set.assert_called_with(test_key, new_value)
redis_instance.get.return_value = new_value
assert store.get(test_key) == new_value

key = "non_existent_key"
default_value = 99
redis_instance.get.return_value = None
assert store.get(key, default_value) == default_value


def test_redis_with_different_instances() -> None:
from autogen_ext.cache_store.redis import RedisStore

redis_instance_1 = MagicMock()
redis_instance_2 = MagicMock()

store_1 = RedisStore[int](redis_instance_1)
store_2 = RedisStore[int](redis_instance_2)

test_key = "test_key"
test_value_1 = 5
test_value_2 = 6

store_1.set(test_key, test_value_1)
redis_instance_1.set.assert_called_with(test_key, test_value_1)
redis_instance_1.get.return_value = test_value_1
assert store_1.get(test_key) == test_value_1

store_2.set(test_key, test_value_2)
redis_instance_2.set.assert_called_with(test_key, test_value_2)
redis_instance_2.get.return_value = test_value_2
assert store_2.get(test_key) == test_value_2
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
import copy
from typing import Any, List, Optional, Tuple, Union
from typing import List, Tuple, Union

import pytest
from autogen_core import CacheStore
from autogen_core import InMemoryStore
from autogen_core.models import (
ChatCompletionCache,
ChatCompletionClient,
CreateResult,
LLMMessage,
ReplayChatCompletionClient,
SystemMessage,
UserMessage,
)


class DictStore(CacheStore):
def __init__(self) -> None:
self._store: dict[str, Any] = {}

def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
return self._store.get(key, default)

def set(self, key: str, value: Any) -> Optional[Any]:
self._store[key] = value
return None
from autogen_ext.models.cache import CHAT_CACHE_VALUE_TYPE, ChatCompletionCache
from autogen_ext.models.replay import ReplayChatCompletionClient


def get_test_data() -> Tuple[list[str], list[str], SystemMessage, ChatCompletionClient, ChatCompletionCache]:
@@ -33,7 +21,8 @@ def get_test_data() -> Tuple[list[str], list[str], SystemMessage, ChatCompletion
system_prompt = SystemMessage(content="This is a system prompt")
replay_client = ReplayChatCompletionClient(responses)
replay_client.set_cached_bool_value(False)
cached_client = ChatCompletionCache(replay_client, store=DictStore())
store = InMemoryStore[CHAT_CACHE_VALUE_TYPE]()
cached_client = ChatCompletionCache(replay_client, store)

return responses, prompts, system_prompt, replay_client, cached_client

Original file line number Diff line number Diff line change
@@ -12,13 +12,8 @@
default_subscription,
message_handler,
)
from autogen_core.models import (
ChatCompletionClient,
CreateResult,
ReplayChatCompletionClient,
SystemMessage,
UserMessage,
)
from autogen_core.models import ChatCompletionClient, CreateResult, SystemMessage, UserMessage
from autogen_ext.models.replay import ReplayChatCompletionClient


@dataclass
36 changes: 32 additions & 4 deletions python/uv.lock