Repository: camel-ai/camel
Pull request: feat: simplify creating agent using str, add examples
## Description

Close #1681.

## Checklist

Go over all the following points, and put an `x` in all the boxes that apply.

- [x] I have read the [CONTRIBUTION](https://github.com/camel-ai/camel/blob/master/CONTRIBUTING.md) guide (**required**)
- [x] I have linked this PR to an issue using the Development section on the right sidebar or by adding `Fixes #issue-number` in the PR description (**required**)
- [x] I have checked if any dependencies need to be added or updated in `pyproject.toml` and `poetry.lock`
- [x] I have added examples if this is a new feature

If you are unsure about any of these, don't hesitate to ask. We are here to help!


Problem statement:
Support `str` like behaviour for `ModelPlatformType` like `ModelType` to simplify interface
The goal is to simplify interface to enable creating a `ChatAgent` with one line of code.

The currect interface for create a `ChatAgent` with a model is like this:
```
from camel.models import ModelFactory
from camel.types import ModelPlatformType, ModelType
from camel.agents import ChatAgent

# Define the model, here in this case we use gpt-4o-mini
model = ModelFactory.create(
    model_platform=ModelPlatformType.OPENAI,
    model_type=ModelType.GPT_4O_MINI,
)

# Initialize the agent
ChatAgent("You are a helpful assistant.", model=model)
```

By supporting `str` like behaviour for `ModelPlatformType` we can do:
```
from camel.models import ModelFactory
from camel.agents import ChatAgent

# Define the model, here in this case we use gpt-4o-mini
model = ModelFactory.create(
    model_platform="openai",
    model_type="gpt-4o-mini",
)

# Initialize the agent
ChatAgent("You are a helpful assistant.", model=model)
```

By creating `model` inside `ChatAgent` with differnt if-else conditions we can do:
```
from camel.agents import ChatAgent

# Initialize the agent with a `tuple`
ChatAgent("You are a helpful assistant.", model=("openai", "gpt-4o-mini"))

# Or just a `str` for model type. Try to find the corresponding `ModelPlatformType` or use default `ModelPlatformType`
ChatAgent("You are a helpful assistant.", model="gpt-4o-mini") 
```

Of course we can also support:
```
from camel.agents import ChatAgent
from camel.types import ModelPlatformType, ModelType

# Initialize the agent with a `tuple` of `enum`
ChatAgent("You are a helpful assistant.", model=(ModelPlatformType.OPENAI, ModelType.GPT_4O_MINI))

# Or just a `enum` for model type. Try to find the corresponding `ModelPlatformType` or use default `ModelPlatformType`
ChatAgent("You are a helpful assistant.", model=ModelType.GPT_4O_MINI) 
```

Hints from issue discussion:

Commit message: create agent using str, add examples

Patch to review:
diff --git a/camel/agents/chat_agent.py b/camel/agents/chat_agent.py
index 6946ec0f4a..abfdc28e6e 100644
--- a/camel/agents/chat_agent.py
+++ b/camel/agents/chat_agent.py
@@ -25,6 +25,7 @@
     List,
     Optional,
     Set,
+    Tuple,
     Type,
     Union,
 )
@@ -107,7 +108,8 @@ class ChatAgent(BaseAgent):
     Args:
         system_message (Union[BaseMessage, str], optional): The system message
             for the chat agent.
-        model (BaseModelBackend, optional): The model backend to use for
+        model (Union[BaseModelBackend, List[BaseModelBackend], Tuple[str, str],
+            str], optional): The model backend to use for
             generating responses. (default: :obj:`ModelPlatformType.DEFAULT`
             with `ModelType.DEFAULT`)
         memory (AgentMemory, optional): The agent memory for managing chat
@@ -144,7 +146,9 @@ def __init__(
         self,
         system_message: Optional[Union[BaseMessage, str]] = None,
         model: Optional[
-            Union[BaseModelBackend, List[BaseModelBackend]]
+            Union[
+                BaseModelBackend, List[BaseModelBackend], Tuple[str, str], str
+            ]
         ] = None,
         memory: Optional[AgentMemory] = None,
         message_window_size: Optional[int] = None,
@@ -158,6 +162,23 @@ def __init__(
         scheduling_strategy: str = "round_robin",
         single_iteration: bool = False,
     ) -> None:
+        # Handle string model specification (just the model type)
+        if isinstance(model, str):
+            # Default to OpenAI platform
+            model_platform = ModelPlatformType.DEFAULT
+            model_type = model
+            model = ModelFactory.create(
+                model_platform=model_platform,
+                model_type=model_type,
+            )
+        # Handle tuple-based model specification
+        elif isinstance(model, tuple) and len(model) == 2:
+            model_platform, model_type = model  # type: ignore[assignment]
+            model = ModelFactory.create(
+                model_platform=model_platform,
+                model_type=model_type,
+            )
+
         # Set up model backend
         self.model_backend = ModelManager(
             (
diff --git a/camel/models/model_factory.py b/camel/models/model_factory.py
index eabdab58f4..2b2a0c2786 100644
--- a/camel/models/model_factory.py
+++ b/camel/models/model_factory.py
@@ -52,8 +52,8 @@ class ModelFactory:
 
     @staticmethod
     def create(
-        model_platform: ModelPlatformType,
-        model_type: Union[ModelType, str],
+        model_platform: Union[ModelPlatformType, str],
+        model_type: Union[ModelType, str, UnifiedModelType],
         model_config_dict: Optional[Dict] = None,
         token_counter: Optional[BaseTokenCounter] = None,
         api_key: Optional[str] = None,
@@ -62,10 +62,12 @@ def create(
         r"""Creates an instance of `BaseModelBackend` of the specified type.
 
         Args:
-            model_platform (ModelPlatformType): Platform from which the model
-                originates.
-            model_type (Union[ModelType, str]): Model for which a
-                backend is created. Can be a `str` for open source platforms.
+            model_platform (Union[ModelPlatformType, str]): Platform from
+                which the model originates. Can be a string or
+                ModelPlatformType enum.
+            model_type (Union[ModelType, str, UnifiedModelType]): Model for
+                which a backend is created. Can be a string, ModelType enum, or
+                UnifiedModelType.
             model_config_dict (Optional[Dict]): A dictionary that will be fed
                 into the backend constructor. (default: :obj:`None`)
             token_counter (Optional[BaseTokenCounter], optional): Token
@@ -84,6 +86,21 @@ def create(
         Raises:
             ValueError: If there is no backend for the model.
         """
+        # Convert string to ModelPlatformType enum if needed
+        if isinstance(model_platform, str):
+            try:
+                model_platform = ModelPlatformType(model_platform)
+            except ValueError:
+                raise ValueError(f"Unknown model platform: {model_platform}")
+
+        # Convert string to ModelType enum or UnifiedModelType if needed
+        if isinstance(model_type, str):
+            try:
+                model_type = ModelType(model_type)
+            except ValueError:
+                # If not in ModelType, create a UnifiedModelType
+                model_type = UnifiedModelType(model_type)
+
         model_class: Optional[Type[BaseModelBackend]] = None
         model_type = UnifiedModelType(model_type)
 
diff --git a/examples/agent/create_agent_one_line.py b/examples/agent/create_agent_one_line.py
new file mode 100644
index 0000000000..7fc80d1aa9
--- /dev/null
+++ b/examples/agent/create_agent_one_line.py
@@ -0,0 +1,61 @@
+# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
+
+from camel.agents import ChatAgent
+
+# Method 1: Initialize the agent with just a string (model name)
+# This uses the default platform (OpenAI)
+agent1 = ChatAgent("You are a helpful assistant.", model="gpt-4o-mini")
+
+# Method 2: Initialize the agent with a tuple (platform, model)
+agent2 = ChatAgent(
+    "You are a helpful assistant.", model=("openai", "gpt-4o-mini")
+)
+
+# Method 3: Initialize with a pre-created model (original approach)
+from camel.models import ModelFactory  # noqa: E402
+from camel.types import ModelPlatformType, ModelType  # noqa: E402
+
+model = ModelFactory.create(
+    model_platform=ModelPlatformType.OPENAI,  # Using enum
+    model_type=ModelType.GPT_4O_MINI,  # Using enum
+)
+agent3 = ChatAgent("You are a helpful assistant.", model=model)
+
+# Method 4: Initialize with a pre-created model using strings
+model = ModelFactory.create(
+    model_platform="openai",  # Using string
+    model_type="gpt-4o-mini",  # Using string
+)
+agent4 = ChatAgent("You are a helpful assistant.", model=model)
+
+# Method 5: Default model when none is specified
+agent5 = ChatAgent("You are a helpful assistant.")
+
+# Test with a simple question
+user_msg = "What is the capital of France?"
+
+# Get the response from one of the agents
+response = agent1.step(user_msg)
+print("Response from agent1 (string model):")
+print(response.msgs[0].content)
+"""
+Response from agent1 (string model):
+The capital of France is Paris.
+"""
+
+# You can test other agents similarly:
+# response = agent2.step(user_msg)
+# print("Response from agent2 (tuple model):")
+# print(response.msgs[0].content)


Code review comments:
path: examples/agent/create_agent_one_line.py
text: @user1:
Can we also support
```
from camel.agents import ChatAgent
from camel.types import ModelPlatformType, ModelType

# Initialize the agent with a `tuple` of `enum`
ChatAgent("You are a helpful assistant.", model=(ModelPlatformType.OPENAI, ModelType.GPT_4O_MINI))

# Or just a `enum` for model type. Try to find the corresponding `ModelPlatformType` or use default `ModelPlatformType`
ChatAgent("You are a helpful assistant.", model=ModelType.GPT_4O_MINI) 
```

diff_hunk: @@ -107,7 +108,8 @@ class ChatAgent(BaseAgent):
     Args:
         system_message (Union[BaseMessage, str], optional): The system message
             for the chat agent.
-        model (BaseModelBackend, optional): The model backend to use for
+        model (Union[BaseModelBackend, List[BaseModelBackend], Tuple[str, str],
+            str], optional): The model backend to use for
path: camel/agents/chat_agent.py
text: @user1:
Let's also allow `Tuple[ModelPlatformType, ModelType]`