Skip to content

Commit

Permalink
feat: enhance source2synth
Browse files Browse the repository at this point in the history
  • Loading branch information
Wendong-Fan committed Jan 18, 2025
1 parent c7bd39c commit 5850463
Show file tree
Hide file tree
Showing 10 changed files with 473 additions and 61 deletions.
38 changes: 35 additions & 3 deletions camel/agents/multi_hop_generator_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,36 @@
ProgrammedAgentInstructionResult,
programmable_capability,
)
from camel.messages import BaseMessage
from camel.synthetic_datagen.source2synth.models import (
from camel.datagen.source2synth.models import (
ContextPrompt,
MultiHopQA,
)
from camel.messages import BaseMessage


class MultiHopGeneratorAgent(ProgrammableChatAgent):
r"""An agent specialized in generating multi-hop question-answer pairs.
This agent is designed to create complex questions that require multiple
steps of reasoning to answer. It analyzes context to identify related
facts and generates questions that require connecting these facts
logically.
Attributes:
model_config (ConfigDict): Configuration for model behavior.
system_message (BaseMessage): System message defining agent's role and
instructions.
"""

model_config = ConfigDict(arbitrary_types_allowed=True)

def __init__(self, **kwargs: Any):
def __init__(self, **kwargs: Any) -> None:
r"""Initialize the MultiHopGeneratorAgent.
Args:
**kwargs (Any): Additional keyword arguments to pass to parent
class.
"""
super().__init__(**kwargs)

system_text: str = textwrap.dedent(
Expand Down Expand Up @@ -64,6 +83,19 @@ def __init__(self, **kwargs: Any):
def generate_multi_hop_qa(
self, context: str
) -> ProgrammedAgentInstructionResult[MultiHopQA]:
r"""Generate a multi-hop question-answer pair from given context.
Args:
context (str): The input text context to generate QA from.
Returns:
ProgrammedAgentInstructionResult[MultiHopQA]: Result containing the
generated question, reasoning steps, answer, and supporting
facts.
Raises:
RuntimeError: If the agent fails to generate a response.
"""
context_prompt = ContextPrompt(
main_context=context, related_contexts=None
)
Expand Down
91 changes: 73 additions & 18 deletions camel/agents/programmed_agent_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@


class ProgrammableAgentRequirement(Enum):
r"""Requirements for programmable agent state.
Defines the possible requirements that can be used to repair the state
of a programmable agent.
Attributes:
LAST_MESSAGE_NOT_USER (str): Requires that the last message in the
conversation was not from the user.
"""

LAST_MESSAGE_NOT_USER = "LAST_MESSAGE_NOT_USER"


Expand All @@ -34,6 +44,11 @@ class ProgrammedAgentInstructionResult(BaseModel, Generic[T]):
Contains the messages exchanged during execution and the computed value.
The value type is specified by the generic type parameter T.
Attributes:
user_message (BaseMessage): The message sent by the user.
agent_message (BaseMessage): The message sent by the agent.
value (T): The computed result value of type T.
"""

user_message: BaseMessage
Expand All @@ -48,8 +63,7 @@ class AbstractProgrammableAgent(abc.ABC):
A programmable agent is an agent that can be programmed to perform a
specific function or task. This class defines the interface for a
programmable
agent.
programmable agent.
These methods should be implemented in order to ensure the agent supports
the necessary guarantees to enable a programming interface while
Expand All @@ -68,16 +82,15 @@ def run_atomic(
An atomic operation is an operation that is guaranteed to
be executed without interruption by any other operation.
If the operation fails or times out the agents state should be
unchanged.
Args:
callback (Callable[[], ProgrammedAgentInstructionResult[T]]): The
operation to execute atomically.
If an operation is already in progress, this method should throw an
exception. (It is up to the caller to do any queuing)
Returns:
ProgrammedAgentInstructionResult[T]: The result of the operation.
If the agent is in a state where it can perform the operation,
it must leave the agent in a state where it can perform the
operation again. Though if state changes in successful operation
improve its ability to perform the operation, it should keep them.
Raises:
RuntimeError: If an operation is already in progress.
"""
raise NotImplementedError

Expand All @@ -86,10 +99,13 @@ def repair_state(self, requirement: ProgrammableAgentRequirement) -> None:
r"""Repair the state of the agent.
Agents may have other non-atomic interfaces, such as a user interface,
or chat between other agents.
or chat between other agents. This method should restore the agent to
a state where it can perform operations according to the specified
requirement.
This method should restore the agent to a state where it can perform
operations according to the specified requirement.
Args:
requirement (ProgrammableAgentRequirement): The requirement to
repair the state for.
"""
raise NotImplementedError

Expand All @@ -99,10 +115,16 @@ def programmable_capability(
) -> Callable[..., ProgrammedAgentInstructionResult[T]]:
r"""Decorator for programmable agent capabilities.
Wraps a method to ensure it is executed atomically via the agent's
run_atomic interface.
The decorated method must return a ProgrammedAgentInstructionResult with
appropriate type parameter.
This decorator ensures that the decorated method is executed atomically
and maintains the agent's state guarantees.
Args:
func (Callable[..., ProgrammedAgentInstructionResult[T]]): The method
to decorate.
Returns:
Callable[..., ProgrammedAgentInstructionResult[T]]: The decorated
method that ensures atomic execution.
"""

@wraps(func)
Expand All @@ -120,16 +142,41 @@ class ProgrammableChatAgent(ChatAgent, AbstractProgrammableAgent):
Provides a default implementation of atomic execution using threading locks
and basic state tracking for message roles. Implementing classes need to
provide specific repair logic for their use cases.
Attributes:
_operation_lock (threading.Lock): Lock for ensuring atomic operations.
_last_message_role (Optional[str]): Role of the last message in the
conversation.
"""

def __init__(self, **kwargs: Any):
def __init__(self, **kwargs: Any) -> None:
r"""Initialize the ProgrammableChatAgent.
Args:
**kwargs (Any): Additional keyword arguments to pass to parent
class.
"""
super().__init__(**kwargs)
self._operation_lock = threading.Lock()
self._last_message_role: Optional[str] = None

def run_atomic(
self, callback: Callable[[], ProgrammedAgentInstructionResult[T]]
) -> ProgrammedAgentInstructionResult[T]:
r"""Run an atomic operation on the agent.
Ensures thread-safe execution of the callback function by using a lock.
Args:
callback (Callable[[], ProgrammedAgentInstructionResult[T]]): The
operation to execute atomically.
Returns:
ProgrammedAgentInstructionResult[T]: The result of the operation.
Raises:
RuntimeError: If an operation is already in progress.
"""
if not self._operation_lock.acquire(blocking=False):
raise RuntimeError("Operation already in progress")

Expand All @@ -141,6 +188,14 @@ def run_atomic(
self._operation_lock.release()

def repair_state(self, requirement: ProgrammableAgentRequirement) -> None:
r"""Repair the state of the agent.
Implements basic state repair for message role requirements.
Args:
requirement (ProgrammableAgentRequirement): The requirement to
repair the state for.
"""
if requirement == ProgrammableAgentRequirement.LAST_MESSAGE_NOT_USER:
if self._last_message_role == "user":
raise NotImplementedError(
Expand Down
31 changes: 31 additions & 0 deletions camel/datagen/source2synth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ========= 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 .data_processor import (
DataCurator,
ExampleConstructor,
UserDataProcessor,
)
from .models import MultiHopQA, ReasoningStep
from .user_data_processor_config import (
ProcessorConfig,
)

__all__ = [
"DataCurator",
"ExampleConstructor",
"ProcessorConfig",
"UserDataProcessor",
"ReasoningStep",
"MultiHopQA",
]
Loading

0 comments on commit 5850463

Please sign in to comment.