Skip to content

Commit

Permalink
Merge branch 'dev_origin' into dev_dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
NeilJohnson0930 committed Feb 13, 2025
2 parents c2e2405 + ad14a38 commit 99bb363
Show file tree
Hide file tree
Showing 24 changed files with 1,166 additions and 1,114 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ body:
attributes:
label: What version of camel are you using?
description: Run command `python3 -c 'print(__import__("camel").__version__)'` in your shell and paste the output here.
placeholder: E.g., 0.2.20
placeholder: E.g., 0.2.21
validations:
required: true

Expand Down
2 changes: 1 addition & 1 deletion camel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from camel.logger import disable_logging, enable_logging, set_log_level

__version__ = '0.2.20'
__version__ = '0.2.21'

__all__ = [
'__version__',
Expand Down
11 changes: 10 additions & 1 deletion camel/embeddings/openai_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class OpenAIEmbedding(BaseEmbedding[str]):
model_type (EmbeddingModelType, optional): The model type to be
used for text embeddings.
(default: :obj:`TEXT_EMBEDDING_3_SMALL`)
url (Optional[str], optional): The url to the OpenAI service.
(default: :obj:`None`)
api_key (str, optional): The API key for authenticating with the
OpenAI service. (default: :obj:`None`)
dimensions (int, optional): The text embedding output dimensions.
Expand All @@ -49,6 +51,7 @@ def __init__(
model_type: EmbeddingModelType = (
EmbeddingModelType.TEXT_EMBEDDING_3_SMALL
),
url: str | None = None,
api_key: str | None = None,
dimensions: int | NotGiven = NOT_GIVEN,
) -> None:
Expand All @@ -61,7 +64,13 @@ def __init__(
assert isinstance(dimensions, int)
self.output_dim = dimensions
self._api_key = api_key or os.environ.get("OPENAI_API_KEY")
self.client = OpenAI(timeout=180, max_retries=3, api_key=self._api_key)
self._url = url or os.environ.get("OPENAI_API_BASE_URL")
self.client = OpenAI(
timeout=180,
max_retries=3,
base_url=self._url,
api_key=self._api_key,
)

def embed_list(
self,
Expand Down
12 changes: 12 additions & 0 deletions camel/interpreters/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.9-slim

# Install R and required dependencies
RUN apt-get update && apt-get install -y \
r-base \
&& rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /workspace

# Keep container running
CMD ["tail", "-f", "/dev/null"]
20 changes: 19 additions & 1 deletion camel/interpreters/docker_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ class DockerInterpreter(BaseInterpreter):
_CODE_EXECUTE_CMD_MAPPING: ClassVar[Dict[str, str]] = {
"python": "python {file_name}",
"bash": "bash {file_name}",
"r": "Rscript {file_name}",
}

_CODE_EXTENSION_MAPPING: ClassVar[Dict[str, str]] = {
"python": "py",
"bash": "sh",
"r": "R",
}

_CODE_TYPE_MAPPING: ClassVar[Dict[str, str]] = {
Expand All @@ -67,6 +69,8 @@ class DockerInterpreter(BaseInterpreter):
"shell": "bash",
"bash": "bash",
"sh": "bash",
"r": "r",
"R": "r",
}

def __init__(
Expand Down Expand Up @@ -104,8 +108,22 @@ def _initialize_if_needed(self) -> None:
import docker

client = docker.from_env()

# Build custom image with Python and R
dockerfile_path = Path(__file__).parent / "docker"
image_tag = "camel-interpreter:latest"
try:
client.images.get(image_tag)
except docker.errors.ImageNotFound:
logger.info("Building custom interpreter image...")
client.images.build(
path=str(dockerfile_path),
tag=image_tag,
rm=True,
)

self._container = client.containers.run(
"python:3.10",
image_tag,
detach=True,
name=f"camel-interpreter-{uuid.uuid4()}",
command="tail -f /dev/null",
Expand Down
103 changes: 97 additions & 6 deletions camel/interpreters/subprocess_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ class SubprocessInterpreter(BaseInterpreter):
_CODE_EXECUTE_CMD_MAPPING: ClassVar[Dict[str, str]] = {
"python": "python {file_name}",
"bash": "bash {file_name}",
"r": "Rscript {file_name}",
}

_CODE_EXTENSION_MAPPING: ClassVar[Dict[str, str]] = {
"python": "py",
"bash": "sh",
"r": "R",
}

_CODE_TYPE_MAPPING: ClassVar[Dict[str, str]] = {
Expand All @@ -63,6 +65,8 @@ class SubprocessInterpreter(BaseInterpreter):
"shell": "bash",
"bash": "bash",
"sh": "bash",
"r": "r",
"R": "r",
}

def __init__(
Expand Down Expand Up @@ -98,15 +102,91 @@ def run_file(
if not file.is_file():
raise RuntimeError(f"{file} is not a file.")
code_type = self._check_code_type(code_type)
cmd = shlex.split(
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
file_name=str(file)
if self._CODE_TYPE_MAPPING[code_type] == "python":
# For Python code, use ast to analyze and modify the code
import ast

import astor

with open(file, 'r') as f:
source = f.read()

# Parse the source code
try:
tree = ast.parse(source)
# Get the last node
if tree.body:
last_node = tree.body[-1]
# Handle expressions that would normally not produce output
# For example: In a REPL, typing '1 + 2' should show '3'

if isinstance(last_node, ast.Expr):
# Only wrap in print(repr()) if it's not already a
# print call
if not (
isinstance(last_node.value, ast.Call)
and isinstance(last_node.value.func, ast.Name)
and last_node.value.func.id == 'print'
):
# Transform the AST to wrap the expression in print
# (repr())
# Example transformation:
# Before: x + y
# After: print(repr(x + y))
tree.body[-1] = ast.Expr(
value=ast.Call(
# Create print() function call
func=ast.Name(id='print', ctx=ast.Load()),
args=[
ast.Call(
# Create repr() function call
func=ast.Name(
id='repr', ctx=ast.Load()
),
# Pass the original expression as
# argument to repr()
args=[last_node.value],
keywords=[],
)
],
keywords=[],
)
)
# Fix missing source locations
ast.fix_missing_locations(tree)
# Convert back to source
modified_source = astor.to_source(tree)
# Create a temporary file with the modified source
temp_file = self._create_temp_file(modified_source, "py")
cmd = shlex.split(f"python {temp_file!s}")
except SyntaxError:
# If parsing fails, run the original file
cmd = shlex.split(
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
file_name=str(file)
)
)
else:
# For non-Python code, use standard execution
cmd = shlex.split(
self._CODE_EXECUTE_CMD_MAPPING[code_type].format(
file_name=str(file)
)
)
)

proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
stdout, stderr = proc.communicate()
return_code = proc.returncode

# Clean up temporary file if it was created
if (
self._CODE_TYPE_MAPPING[code_type] == "python"
and 'temp_file' in locals()
):
temp_file.unlink()

if self.print_stdout and stdout:
print("======stdout======")
print(Fore.GREEN + stdout + Fore.RESET)
Expand All @@ -115,8 +195,19 @@ def run_file(
print("======stderr======")
print(Fore.RED + stderr + Fore.RESET)
print("==================")
exec_result = f"{stdout}"
exec_result += f"(stderr: {stderr})" if stderr else ""

# Build the execution result
exec_result = ""
if stdout:
exec_result += stdout
if stderr:
exec_result += f"(stderr: {stderr})"
if return_code != 0:
error_msg = f"(Execution failed with return code {return_code})"
if not stderr:
exec_result += error_msg
elif error_msg not in stderr:
exec_result += error_msg
return exec_result

def run(
Expand Down
38 changes: 38 additions & 0 deletions camel/toolkits/sympy_toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,43 @@ def compute_rank(self, matrix: List[List[float]]) -> str:
except Exception as e:
return self.handle_exception("compute_rank", e)

def compute_inner_product(
self, vector1: List[float], vector2: List[float]
) -> str:
r"""Computes the inner (dot) product of two vectors.
Args:
vector1 (List[float]): The first vector as a list of floats.
vector2 (List[float]): The second vector as a list of floats.
Returns:
str: JSON string containing the inner product in the `"result"`
field. If an error occurs, the JSON string will include an
`"error"` field with the corresponding error message.
Raises:
ValueError: If the vectors have different dimensions.
"""
import sympy as sp

try:
# Convert the lists into sympy Matrix objects (column vectors)
v1 = sp.Matrix(vector1)
v2 = sp.Matrix(vector2)

# Check that the vectors have the same dimensions.
if v1.shape != v2.shape:
raise ValueError(
"Vectors must have the same dimensions to compute "
"the inner product."
)

# Compute the dot (inner) product.
inner_product = v1.dot(v2)
return json.dumps({"result": str(inner_product)})
except Exception as e:
return self.handle_exception("compute_inner_product", e)

def handle_exception(self, func_name: str, error: Exception) -> str:
r"""Handles exceptions by logging and returning error details.
Expand Down Expand Up @@ -775,4 +812,5 @@ def get_tools(self) -> List[FunctionTool]:
FunctionTool(self.compute_eigenvectors),
FunctionTool(self.compute_nullspace),
FunctionTool(self.compute_rank),
FunctionTool(self.compute_inner_product),
]
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
project = 'CAMEL'
copyright = '2024, CAMEL-AI.org'
author = 'CAMEL-AI.org'
release = '0.2.20'
release = '0.2.21'

html_favicon = (
'https://raw.githubusercontent.com/camel-ai/camel/master/misc/favicon.png'
Expand Down
2 changes: 1 addition & 1 deletion docs/get_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ conda create --name camel python=3.10
conda activate camel
# Clone github repo
git clone -b v0.2.20 https://github.com/camel-ai/camel.git
git clone -b v0.2.21 https://github.com/camel-ai/camel.git
# Change directory into project directory
cd camel
Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Main Documentation
:caption: Key Modules
:name: key_modules

key_modules/agents.md
key_modules/datagen.md
key_modules/models.md
key_modules/messages.md
key_modules/memory.md
Expand Down
Loading

0 comments on commit 99bb363

Please sign in to comment.