Replace create_completion_client_from_env with component config (#4928)

* Replace create_completion_client_from_env with component config

* json load
This commit is contained in:
Jack Gerrits 2025-01-08 09:33:28 -05:00 committed by GitHub
parent b850dcd399
commit 538f39497b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 99 additions and 127 deletions

View File

@ -1,4 +1,5 @@
import asyncio
import json
import logging
import os
import re
@ -10,7 +11,7 @@ from typing import List
from autogen_core import AgentId, AgentProxy, TopicId
from autogen_core import SingleThreadedAgentRuntime
from autogen_core.logging import EVENT_LOGGER_NAME
from autogen_core import EVENT_LOGGER_NAME
from autogen_core.models import (
ChatCompletionClient,
UserMessage,
@ -26,7 +27,7 @@ from autogen_magentic_one.agents.orchestrator import LedgerOrchestrator
from autogen_magentic_one.messages import BroadcastMessage
from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfer
from autogen_magentic_one.agents.file_surfer import FileSurfer
from autogen_magentic_one.utils import LogHandler, message_content_to_str, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler, message_content_to_str
encoding = None
def count_token(value: str) -> int:
@ -123,10 +124,8 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Create the AzureOpenAI client from the environment file
client = create_completion_client_from_env()
mlm_client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
mlm_client = ChatCompletionClient.load_component(json.loads(os.environ["MLM_CHAT_COMPLETION_CLIENT_CONFIG"]))
# Register agents.

View File

@ -1,4 +1,5 @@
import asyncio
import json
import logging
import os
import re
@ -27,7 +28,7 @@ from autogen_magentic_one.agents.orchestrator import LedgerOrchestrator
from autogen_magentic_one.messages import BroadcastMessage
from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfer
from autogen_magentic_one.agents.file_surfer import FileSurfer
from autogen_magentic_one.utils import LogHandler, message_content_to_str, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler, message_content_to_str
encoding = None
def count_token(value: str) -> int:
@ -124,11 +125,10 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Create the AzureOpenAI client, with AAD auth, from environment
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
mlm_client = ChatCompletionClient.load_component(json.loads(os.environ["MLM_CHAT_COMPLETION_CLIENT_CONFIG"]))
mlm_client = create_completion_client_from_env()
# Register agents.
await runtime.register(
"Assistant",

View File

@ -13,7 +13,6 @@ from autogen_core.models import (
from autogen_magentic_one.agents.coder import Coder, Executor
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.messages import BroadcastMessage, OrchestrationEvent
from autogen_magentic_one.utils import create_completion_client_from_env
async def main() -> None:
@ -21,7 +20,8 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Create the AzureOpenAI client
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
# Register agents.
await runtime.register(

View File

@ -24,7 +24,7 @@ from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator, Led
from autogen_magentic_one.messages import BroadcastMessage, OrchestrationEvent, RequestReplyMessage, ResetMessage, DeactivateMessage
from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfer
from autogen_magentic_one.agents.file_surfer import FileSurfer
from autogen_magentic_one.utils import LogHandler, message_content_to_str, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler, message_content_to_str
import evaluation_harness
@ -120,7 +120,8 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Create the AzureOpenAI client, with AAD auth
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
# Login assistant
await runtime.register(
"LoginAssistant",

View File

@ -119,28 +119,39 @@ playwright install --with-deps chromium
## Environment Configuration for Chat Completion Client
This guide outlines how to configure your environment to use the `create_completion_client_from_env` function, which reads environment variables to return an appropriate `ChatCompletionClient`.
This guide outlines how to structure the config to load a ChatCompletionClient for Magentic-One.
```python
from autogen_core.models import ChatCompletionClient
config = {}
client = ChatCompletionClient.load_component(config)
```
Currently, Magentic-One only supports OpenAI's GPT-4o as the underlying LLM.
### Azure OpenAI service
To configure for Azure OpenAI service, set the following environment variables:
- `CHAT_COMPLETION_PROVIDER='azure'`
- `CHAT_COMPLETION_KWARGS_JSON` with the following JSON structure:
To configure for Azure OpenAI service, use the following config:
```json
{
"api_version": "2024-02-15-preview",
"azure_endpoint": "REPLACE_WITH_YOUR_ENDPOINT",
"model_capabilities": {
"function_calling": true,
"json_output": true,
"vision": true
},
"azure_ad_token_provider": "DEFAULT",
"model": "gpt-4o-2024-05-13"
"provider": "AzureOpenAIChatCompletionClient",
"config": {
"model": "gpt-4o-2024-05-13",
"azure_endpoint": "https://{your-custom-endpoint}.openai.azure.com/",
"azure_deployment": "{your-azure-deployment}",
"api_version": "2024-06-01",
"azure_ad_token_provider": {
"provider": "autogen_ext.models.openai.AzureTokenProvider",
"config": {
"provider_kind": "DefaultAzureCredential",
"scopes": [
"https://cognitiveservices.azure.com/.default"
]
}
}
}
}
```
@ -150,19 +161,34 @@ Log in to Azure using `az login`, and then run the examples. The account used mu
Note that even if you are the owner of the subscription, you still need to grant the necessary Azure Cognitive Services OpenAI permissions to call the API.
Or, to use an API key:
```json
{
"provider": "AzureOpenAIChatCompletionClient",
"config": {
"model": "gpt-4o-2024-05-13",
"azure_endpoint": "https://{your-custom-endpoint}.openai.azure.com/",
"azure_deployment": "{your-azure-deployment}",
"api_version": "2024-06-01",
"api_key": "REPLACE_WITH_YOUR_API_KEY"
}
}
```
### With OpenAI
To configure for OpenAI, set the following environment variables:
- `CHAT_COMPLETION_PROVIDER='openai'`
- `CHAT_COMPLETION_KWARGS_JSON` with the following JSON structure:
To configure for OpenAI, use the following config:
```json
{
"api_key": "REPLACE_WITH_YOUR_API",
"model": "gpt-4o-2024-05-13"
"provider": "OpenAIChatCompletionClient",
"config": {
"model": "gpt-4o-2024-05-13",
"api_key": "REPLACE_WITH_YOUR_API_KEY"
}
}
```
Feel free to replace the model with newer versions of gpt-4o if needed.
### Other Keys (Optional)

View File

@ -2,11 +2,13 @@
import argparse
import asyncio
import json
import logging
import os
from autogen_core import EVENT_LOGGER_NAME, AgentId, AgentProxy, SingleThreadedAgentRuntime
from autogen_core.code_executor import CodeBlock
from autogen_core.models._model_client import ChatCompletionClient
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_magentic_one.agents.coder import Coder, Executor
from autogen_magentic_one.agents.file_surfer import FileSurfer
@ -14,7 +16,7 @@ from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfe
from autogen_magentic_one.agents.orchestrator import LedgerOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import RequestReplyMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
# NOTE: Don't forget to 'playwright install --with-deps chromium'
@ -32,7 +34,8 @@ async def main(logs_dir: str, hil_mode: bool, save_screenshots: bool) -> None:
runtime = SingleThreadedAgentRuntime()
# Create an appropriate client
client = create_completion_client_from_env(model="gpt-4o")
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
assert client.model_info["family"] == "gpt-4o", "This example requires the gpt-4o model"
async with DockerCommandLineCodeExecutor(work_dir=logs_dir) as code_executor:
# Register agents.

View File

@ -5,16 +5,19 @@ round-robin orchestrator agent. The code snippets are executed inside a docker c
"""
import asyncio
import json
import logging
import os
from autogen_core import EVENT_LOGGER_NAME, AgentId, AgentProxy, SingleThreadedAgentRuntime
from autogen_core.code_executor import CodeBlock
from autogen_core.models._model_client import ChatCompletionClient
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_magentic_one.agents.coder import Coder, Executor
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import RequestReplyMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
async def confirm_code(code: CodeBlock) -> bool:
@ -29,9 +32,10 @@ async def main() -> None:
# Create the runtime.
runtime = SingleThreadedAgentRuntime()
model_client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
async with DockerCommandLineCodeExecutor() as code_executor:
# Register agents.
await Coder.register(runtime, "Coder", lambda: Coder(model_client=create_completion_client_from_env()))
await Coder.register(runtime, "Coder", lambda: Coder(model_client=model_client))
coder = AgentProxy(AgentId("Coder", "default"), runtime)
await Executor.register(

View File

@ -3,14 +3,17 @@ to navigate the file system. The human user and the file surfer agent takes turn
to write input or perform actions, orchestrated by an round-robin orchestrator agent."""
import asyncio
import json
import logging
import os
from autogen_core import EVENT_LOGGER_NAME, AgentId, AgentProxy, SingleThreadedAgentRuntime
from autogen_core.models._model_client import ChatCompletionClient
from autogen_magentic_one.agents.file_surfer import FileSurfer
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import RequestReplyMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
async def main() -> None:
@ -18,7 +21,7 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Get an appropriate client
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
# Register agents.
await FileSurfer.register(runtime, "file_surfer", lambda: FileSurfer(model_client=client))

View File

@ -5,16 +5,19 @@ round-robin orchestrator agent.
The code snippets are not executed in this example."""
import asyncio
import json
import logging
import os
from autogen_core import EVENT_LOGGER_NAME, AgentId, AgentProxy, SingleThreadedAgentRuntime
# from typing import Any, Dict, List, Tuple, Union
from autogen_core.models._model_client import ChatCompletionClient
from autogen_magentic_one.agents.coder import Coder
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import RequestReplyMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
async def main() -> None:
@ -22,7 +25,7 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Get an appropriate client
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
# Register agents.
await Coder.register(runtime, "Coder", lambda: Coder(model_client=client))

View File

@ -4,15 +4,17 @@ The human user and the web surfer agent takes turn to write input or perform act
orchestrated by an round-robin orchestrator agent."""
import asyncio
import json
import logging
import os
from autogen_core import EVENT_LOGGER_NAME, AgentId, AgentProxy, SingleThreadedAgentRuntime
from autogen_core.models import ChatCompletionClient
from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfer
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import RequestReplyMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
# NOTE: Don't forget to 'playwright install --with-deps chromium'
@ -22,7 +24,8 @@ async def main() -> None:
runtime = SingleThreadedAgentRuntime()
# Create an appropriate client
client = create_completion_client_from_env(model="gpt-4o")
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
assert client.model_info["family"] == "gpt-4o", "This example requires the gpt-4o model"
# Register agents.
await MultimodalWebSurfer.register(runtime, "WebSurfer", MultimodalWebSurfer)

View File

@ -10,6 +10,7 @@ from autogen_core import SingleThreadedAgentRuntime
from autogen_core import EVENT_LOGGER_NAME
from autogen_core import AgentId, AgentProxy
from autogen_core import DefaultTopicId
from autogen_core.models._model_client import ChatCompletionClient
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
from autogen_core.code_executor import CodeBlock
@ -19,7 +20,7 @@ from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfe
from autogen_magentic_one.agents.orchestrator import LedgerOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import BroadcastMessage
from autogen_magentic_one.utils import LogHandler, create_completion_client_from_env
from autogen_magentic_one.utils import LogHandler
from autogen_core.models import UserMessage
from threading import Lock
@ -60,7 +61,9 @@ class MagenticOneHelper:
logger.handlers = [self.log_handler]
# Create client
client = create_completion_client_from_env(model="gpt-4o")
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
assert client.model_info["family"] == "gpt-4o", "This example requires the gpt-4o model"
# Set up code executor
self.code_executor = DockerCommandLineCodeExecutor(work_dir=self.logs_dir)

View File

@ -1,17 +1,11 @@
import json
import logging
import os
from dataclasses import asdict
from datetime import datetime
from typing import Any, Dict, List, Literal
from autogen_core import Image
from autogen_core.logging import LLMCallEvent
from autogen_core.models import (
ChatCompletionClient,
ModelCapabilities, # type: ignore
)
from autogen_ext.models.openai import AzureOpenAIChatCompletionClient, OpenAIChatCompletionClient
from .messages import (
AgentEvent,
@ -23,62 +17,6 @@ from .messages import (
WebSurferEvent,
)
ENVIRON_KEY_CHAT_COMPLETION_PROVIDER = "CHAT_COMPLETION_PROVIDER"
ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON = "CHAT_COMPLETION_KWARGS_JSON"
# The singleton _default_azure_ad_token_provider, which will be created if needed
_default_azure_ad_token_provider = None
# Create a model client based on information provided in environment variables.
def create_completion_client_from_env(env: Dict[str, str] | None = None, **kwargs: Any) -> ChatCompletionClient:
global _default_azure_ad_token_provider
"""
Create a model client based on information provided in environment variables.
env (Optional): When provied, read from this dictionary rather than os.environ
kwargs**: ChatClient arguments to override (e.g., model)
NOTE: If 'azure_ad_token_provider' is included, and euquals the string 'DEFAULT' then replace it with
azure.identity.get_bearer_token_provider(DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default")
"""
# If a dictionary was not provided, load it from the environment
if env is None:
env = dict()
env.update(os.environ)
# Load the kwargs, and override with provided kwargs
_kwargs = json.loads(env.get(ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON, "{}"))
_kwargs.update(kwargs)
# If model capabilities were provided, deserialize them as well
if "model_capabilities" in _kwargs:
_kwargs["model_capabilities"] = ModelCapabilities( # type: ignore
vision=_kwargs["model_capabilities"].get("vision"),
function_calling=_kwargs["model_capabilities"].get("function_calling"),
json_output=_kwargs["model_capabilities"].get("json_output"),
)
# Figure out what provider we are using. Default to OpenAI
_provider = env.get(ENVIRON_KEY_CHAT_COMPLETION_PROVIDER, "openai").lower().strip()
# Instantiate the correct client
if _provider == "openai":
return OpenAIChatCompletionClient(**_kwargs) # type: ignore
elif _provider == "azure":
if _kwargs.get("azure_ad_token_provider", "").lower() == "default":
if _default_azure_ad_token_provider is None:
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
_default_azure_ad_token_provider = get_bearer_token_provider(
DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
)
_kwargs["azure_ad_token_provider"] = _default_azure_ad_token_provider
return AzureOpenAIChatCompletionClient(**_kwargs) # type: ignore
else:
raise ValueError(f"Unknown OAI provider '{_provider}'")
# Convert UserContent to a string
def message_content_to_str(

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python3 -m pytest
import asyncio
import json
import os
import re
from json import dumps
@ -12,6 +13,7 @@ from autogen_core import AgentId, AgentProxy, FunctionCall, SingleThreadedAgentR
from autogen_core.models import (
UserMessage,
)
from autogen_core.models._model_client import ChatCompletionClient
from autogen_core.tools._base import ToolSchema
from autogen_magentic_one.agents.multimodal_web_surfer import MultimodalWebSurfer
from autogen_magentic_one.agents.multimodal_web_surfer.tool_definitions import (
@ -25,11 +27,6 @@ from autogen_magentic_one.agents.multimodal_web_surfer.tool_definitions import (
from autogen_magentic_one.agents.orchestrator import RoundRobinOrchestrator
from autogen_magentic_one.agents.user_proxy import UserProxy
from autogen_magentic_one.messages import BroadcastMessage
from autogen_magentic_one.utils import (
ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON,
ENVIRON_KEY_CHAT_COMPLETION_PROVIDER,
create_completion_client_from_env,
)
from conftest import MOCK_CHAT_COMPLETION_KWARGS, reason
from openai import AuthenticationError
@ -57,7 +54,7 @@ skip_all = False
# Search currently does not require an API key
skip_bing = False
if os.getenv(ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON):
if os.getenv("CHAT_COMPLETION_CLIENT_CONFIG"):
skip_openai = False
else:
skip_openai = True
@ -99,14 +96,10 @@ async def make_browser_request(browser: MultimodalWebSurfer, tool: ToolSchema, a
@pytest.mark.skip(reason="Need to fix this test to use a local website instead of a public one.")
@pytest.mark.asyncio
async def test_web_surfer() -> None:
env = {
ENVIRON_KEY_CHAT_COMPLETION_PROVIDER: "openai",
ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON: MOCK_CHAT_COMPLETION_KWARGS,
}
runtime = SingleThreadedAgentRuntime()
# Create an appropriate client
client = create_completion_client_from_env(env)
config = {"provider": "OpenAIChatCompletionClient", "config": json.loads(MOCK_CHAT_COMPLETION_KWARGS)}
client = ChatCompletionClient.load_component(config)
# Register agents.
@ -183,7 +176,7 @@ async def test_web_surfer_oai() -> None:
runtime = SingleThreadedAgentRuntime()
# Create an appropriate client
client = create_completion_client_from_env()
client = ChatCompletionClient.load_component(json.loads(os.environ["CHAT_COMPLETION_CLIENT_CONFIG"]))
# Register agents.
await MultimodalWebSurfer.register(
@ -247,14 +240,10 @@ async def test_web_surfer_oai() -> None:
)
@pytest.mark.asyncio
async def test_web_surfer_bing() -> None:
env = {
ENVIRON_KEY_CHAT_COMPLETION_PROVIDER: "openai",
ENVIRON_KEY_CHAT_COMPLETION_KWARGS_JSON: MOCK_CHAT_COMPLETION_KWARGS,
}
runtime = SingleThreadedAgentRuntime()
# Create an appropriate client
client = create_completion_client_from_env(env)
config = {"provider": "OpenAIChatCompletionClient", "config": json.loads(MOCK_CHAT_COMPLETION_KWARGS)}
client = ChatCompletionClient.load_component(config)
# Register agents.
await MultimodalWebSurfer.register(