From c611dfc7e5711f6c6f6b2e604bd89c0b809484cc Mon Sep 17 00:00:00 2001
From: Aymeric Roucher <69208727+aymeric-roucher@users.noreply.github.com>
Date: Mon, 13 Jan 2025 17:23:03 +0100
Subject: [PATCH 1/9] Clean local python interpreter: propagate imports (#175)
---
examples/benchmark.ipynb | 270 ++++++++--
src/smolagents/agents.py | 50 +-
src/smolagents/e2b_executor.py | 11 +-
src/smolagents/gradio_ui.py | 29 +-
src/smolagents/local_python_executor.py | 638 ++++++++++++++++++------
src/smolagents/models.py | 2 +-
tests/test_agents.py | 8 +-
7 files changed, 763 insertions(+), 245 deletions(-)
diff --git a/examples/benchmark.ipynb b/examples/benchmark.ipynb
index 7a7b776e5..1009f2807 100644
--- a/examples/benchmark.ipynb
+++ b/examples/benchmark.ipynb
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
@@ -16,20 +16,21 @@
}
],
"source": [
- "!pip install -e .. sympy numpy matplotlib seaborn -q # Install dev version of smolagents + some packages"
+ "!pip install -e .. datasets sympy numpy matplotlib seaborn -q # Install dev version of smolagents + some packages"
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "Using the latest cached version of the dataset since m-ric/smolagentsbenchmark couldn't be found on the Hugging Face Hub\n",
- "Found the latest cached dataset configuration 'default' at /Users/aymeric/.cache/huggingface/datasets/m-ric___smolagentsbenchmark/default/0.0.0/0ad5fb2293ab185eece723a4ac0e4a7188f71add (last modified on Wed Jan 8 17:50:13 2025).\n"
+ "/Users/aymeric/venv/test/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
+ " from .autonotebook import tqdm as notebook_tqdm\n",
+ "Generating train split: 100%|██████████| 132/132 [00:00<00:00, 17393.36 examples/s]\n"
]
},
{
@@ -172,7 +173,7 @@
"[132 rows x 4 columns]"
]
},
- "execution_count": 3,
+ "execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
@@ -181,7 +182,7 @@
"import datasets\n",
"import pandas as pd\n",
"\n",
- "eval_ds = datasets.load_dataset(\"m-ric/smolagentsbenchmark\")[\"train\"]\n",
+ "eval_ds = datasets.load_dataset(\"m-ric/smol_agents_benchmark\")[\"train\"]\n",
"pd.DataFrame(eval_ds)"
]
},
@@ -195,9 +196,19 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 6,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/Users/aymeric/venv/test/lib/python3.12/site-packages/pydantic/_internal/_config.py:345: UserWarning: Valid config keys have changed in V2:\n",
+ "* 'fields' has been removed\n",
+ " warnings.warn(message, UserWarning)\n"
+ ]
+ }
+ ],
"source": [
"import time\n",
"import json\n",
@@ -351,6 +362,7 @@
" model_answer: str,\n",
" ground_truth: str,\n",
") -> bool:\n",
+ " \"\"\"Scoring function used to score functions from the GAIA benchmark\"\"\"\n",
" if is_float(ground_truth):\n",
" normalized_answer = normalize_number_str(str(model_answer))\n",
" return normalized_answer == float(ground_truth)\n",
@@ -396,9 +408,100 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 7,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'meta-llama/Llama-3.3-70B-Instruct'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 27061.35it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 34618.15it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'Qwen/Qwen2.5-72B-Instruct'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 33008.29it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 36292.90it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'Qwen/Qwen2.5-Coder-32B-Instruct'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 29165.47it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 30378.50it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'meta-llama/Llama-3.2-3B-Instruct'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 33453.06it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 34763.79it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'meta-llama/Llama-3.1-8B-Instruct'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 35246.25it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 28551.81it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'mistralai/Mistral-Nemo-Instruct-2407'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 32441.59it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 35542.67it/s]\n"
+ ]
+ }
+ ],
"source": [
"open_model_ids = [\n",
" \"meta-llama/Llama-3.3-70B-Instruct\",\n",
@@ -451,9 +554,42 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 8,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'gpt-4o'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 36136.55it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 33451.04it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 39146.44it/s]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Evaluating 'anthropic/claude-3-5-sonnet-latest'...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 132/132 [00:00<00:00, 31512.79it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 33576.82it/s]\n",
+ "100%|██████████| 132/132 [00:00<00:00, 36075.33it/s]\n"
+ ]
+ }
+ ],
"source": [
"from smolagents import LiteLLMModel\n",
"\n",
@@ -495,7 +631,7 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
@@ -534,14 +670,14 @@
},
{
"cell_type": "code",
- "execution_count": 31,
+ "execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/ipykernel_74415/3026956094.py:163: UserWarning: Answer lists have different lengths, returning False.\n",
+ "/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/ipykernel_6037/1901135017.py:164: UserWarning: Answer lists have different lengths, returning False.\n",
" warnings.warn(\n"
]
}
@@ -552,9 +688,25 @@
"\n",
"res = []\n",
"for file_path in glob.glob(\"output/*.jsonl\"):\n",
- " smoldf = pd.read_json(file_path, lines=True)\n",
- " smoldf[\"action_type\"] = \"vanilla\" if \"-vanilla-\" in file_path else \"code\"\n",
- " res.append(smoldf)\n",
+ " data = []\n",
+ " with open(file_path) as f:\n",
+ " for line in f:\n",
+ " try:\n",
+ " # Use standard json module instead of pandas.json to handle large numbers better\n",
+ " record = json.loads(line)\n",
+ " data.append(record)\n",
+ " except json.JSONDecodeError as e:\n",
+ " print(f\"Error parsing line in {file_path}: {e}\")\n",
+ " continue\n",
+ "\n",
+ " try:\n",
+ " smoldf = pd.DataFrame(data)\n",
+ " smoldf[\"action_type\"] = \"vanilla\" if \"-vanilla-\" in file_path else \"code\"\n",
+ " res.append(smoldf)\n",
+ " except Exception as e:\n",
+ " print(f\"Error creating DataFrame from {file_path}: {e}\")\n",
+ " continue\n",
+ "\n",
"result_df = pd.concat(res)\n",
"\n",
"\n",
@@ -579,7 +731,7 @@
},
{
"cell_type": "code",
- "execution_count": 33,
+ "execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
@@ -600,7 +752,7 @@
},
{
"cell_type": "code",
- "execution_count": 34,
+ "execution_count": 15,
"metadata": {},
"outputs": [
{
@@ -643,7 +795,7 @@
"
Qwen/Qwen2.5-72B-Instruct | \n",
" MATH | \n",
" 74.0 | \n",
- " 31.9 | \n",
+ " 30.0 | \n",
" \n",
" \n",
" | 2 | \n",
@@ -778,33 +930,57 @@
" 84.0 | \n",
" 12.0 | \n",
"
\n",
+ " \n",
+ " | 21 | \n",
+ " mistralai/Mistral-Nemo-Instruct-2407 | \n",
+ " GAIA | \n",
+ " 3.1 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 22 | \n",
+ " mistralai/Mistral-Nemo-Instruct-2407 | \n",
+ " MATH | \n",
+ " 20.0 | \n",
+ " 22.0 | \n",
+ "
\n",
+ " \n",
+ " | 23 | \n",
+ " mistralai/Mistral-Nemo-Instruct-2407 | \n",
+ " SimpleQA | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ "
\n",
" \n",
"\n",
""
],
"text/plain": [
- "action_type model_id source code vanilla\n",
- "0 Qwen/Qwen2.5-72B-Instruct GAIA 28.1 6.2\n",
- "1 Qwen/Qwen2.5-72B-Instruct MATH 74.0 31.9\n",
- "2 Qwen/Qwen2.5-72B-Instruct SimpleQA 70.0 10.0\n",
- "3 Qwen/Qwen2.5-Coder-32B-Instruct GAIA 18.8 3.1\n",
- "4 Qwen/Qwen2.5-Coder-32B-Instruct MATH 76.0 60.0\n",
- "5 Qwen/Qwen2.5-Coder-32B-Instruct SimpleQA 86.0 8.0\n",
- "6 anthropic/claude-3-5-sonnet-latest GAIA 40.6 3.1\n",
- "7 anthropic/claude-3-5-sonnet-latest MATH 67.0 50.0\n",
- "8 anthropic/claude-3-5-sonnet-latest SimpleQA 90.0 34.0\n",
- "9 gpt-4o GAIA 28.1 3.1\n",
- "10 gpt-4o MATH 70.0 40.0\n",
- "11 gpt-4o SimpleQA 88.0 6.0\n",
- "12 meta-llama/Llama-3.1-8B-Instruct GAIA 0.0 0.0\n",
- "13 meta-llama/Llama-3.1-8B-Instruct MATH 42.0 18.0\n",
- "14 meta-llama/Llama-3.1-8B-Instruct SimpleQA 54.0 6.0\n",
- "15 meta-llama/Llama-3.2-3B-Instruct GAIA 3.1 0.0\n",
- "16 meta-llama/Llama-3.2-3B-Instruct MATH 32.0 12.0\n",
- "17 meta-llama/Llama-3.2-3B-Instruct SimpleQA 4.0 0.0\n",
- "18 meta-llama/Llama-3.3-70B-Instruct GAIA 34.4 3.1\n",
- "19 meta-llama/Llama-3.3-70B-Instruct MATH 82.0 40.0\n",
- "20 meta-llama/Llama-3.3-70B-Instruct SimpleQA 84.0 12.0"
+ "action_type model_id source code vanilla\n",
+ "0 Qwen/Qwen2.5-72B-Instruct GAIA 28.1 6.2\n",
+ "1 Qwen/Qwen2.5-72B-Instruct MATH 74.0 30.0\n",
+ "2 Qwen/Qwen2.5-72B-Instruct SimpleQA 70.0 10.0\n",
+ "3 Qwen/Qwen2.5-Coder-32B-Instruct GAIA 18.8 3.1\n",
+ "4 Qwen/Qwen2.5-Coder-32B-Instruct MATH 76.0 60.0\n",
+ "5 Qwen/Qwen2.5-Coder-32B-Instruct SimpleQA 86.0 8.0\n",
+ "6 anthropic/claude-3-5-sonnet-latest GAIA 40.6 3.1\n",
+ "7 anthropic/claude-3-5-sonnet-latest MATH 67.0 50.0\n",
+ "8 anthropic/claude-3-5-sonnet-latest SimpleQA 90.0 34.0\n",
+ "9 gpt-4o GAIA 28.1 3.1\n",
+ "10 gpt-4o MATH 70.0 40.0\n",
+ "11 gpt-4o SimpleQA 88.0 6.0\n",
+ "12 meta-llama/Llama-3.1-8B-Instruct GAIA 0.0 0.0\n",
+ "13 meta-llama/Llama-3.1-8B-Instruct MATH 42.0 18.0\n",
+ "14 meta-llama/Llama-3.1-8B-Instruct SimpleQA 54.0 6.0\n",
+ "15 meta-llama/Llama-3.2-3B-Instruct GAIA 3.1 0.0\n",
+ "16 meta-llama/Llama-3.2-3B-Instruct MATH 32.0 12.0\n",
+ "17 meta-llama/Llama-3.2-3B-Instruct SimpleQA 4.0 0.0\n",
+ "18 meta-llama/Llama-3.3-70B-Instruct GAIA 34.4 3.1\n",
+ "19 meta-llama/Llama-3.3-70B-Instruct MATH 82.0 40.0\n",
+ "20 meta-llama/Llama-3.3-70B-Instruct SimpleQA 84.0 12.0\n",
+ "21 mistralai/Mistral-Nemo-Instruct-2407 GAIA 3.1 0.0\n",
+ "22 mistralai/Mistral-Nemo-Instruct-2407 MATH 20.0 22.0\n",
+ "23 mistralai/Mistral-Nemo-Instruct-2407 SimpleQA 30.0 0.0"
]
},
"metadata": {},
@@ -817,12 +993,12 @@
},
{
"cell_type": "code",
- "execution_count": 36,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
- "image/png": "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f4/b5l0v3bQfRy3YvGm6P4dccRTtMvevTctixU7YVJO5/brvi/pxlPvOtbmpYBw177ywXShSf5+pz3e+qIM4yk8ACfNF09/PmWOmzp5qFyxPYjuaL2hxgwYNKvdpCFEWKlZYHzZsmLn44ovNG2+8kf7dN998Y/r06WPeeecd07btv1mp3bt3NzNnzjQdOnQo09kKIYQQQgghhBBCCFFdSFgX1Yw3ZFhZLL744mby5Mm2znrTpk3T5WFatmxp2rRpU2fb999/v0xnKYQQQgghhBBCCCGEEKLaqNgCpKuvvroV1EePHp3+3ahRo2zZl8bzaocJIYQQQgghhBBCCCGEEKWmYhXqVq1amZ122smcf/75ZsyYMeaFF14wd955p9l///3LfWpCCCGEEEIIIYQQQgghqpiKrbEO06ZNs8L6iBEjzEILLWQOPvhg069fv3KflhBCCCGEEEIIIYQQQogqpmIz1l3W+hVXXGE+/PBD89prr0lUr3L++OMPu6Dt5ptvbtZaay2z7bbbmjvuuMPW4ReiUpCdiqTAot8PPfRQ+uf99tvPDBgwoGTHX2211exi5ELUl6lTp5qhQ4fmtS1t8Y477lhSWxcNu88fNmxYwX9/+umn2w9gk7TDQsSJbFQkAdmpECLJVLSwLoRj/PjxZvfddzffffedufLKK83TTz9tjj76aDN48GBz5JFHmjlz5pT7FIWQnYpE8cwzz5hbbrmlbMd//fXXzTrrrFO244uGw913320effTRvLalrODnn39e9HMS1cFVV11lXnnllXKfhhChyEZFEpCdCiGSTNNyn4AQ+XDppZeapZZaytx2222mSZMm9nfLLLOMWXvttW1G8AMPPGD23Xffcp+mqHJkpyJJlLsSXIcOHcp6fFF9tvzDDz+Ye++916y88spFPydRHZS7HRUiF7JRkQRkp0KIJKOMdVHxTJ482S5ee+ihh6bFSseSSy5pdt11V/Pggw+a9ddf34wcOTL9Xa9evcxpp52W/vmaa64xp5xyiv3/L7/80k4R69q1q9l6661tRrGD6WMnn3yyOe+888y6665rNtpoI3P77beX5FpFcpGdinIxatQos/fee9vSQwziYIO///67eeyxx6z93HDDDWaDDTYw3bt3N5dddpkNXijBcsYZZ5iff/7ZlmT56aef0rMuDjnkENOlSxdrc2+++Wb6OGx3/fXX230dccQR9neUauPYHHeLLbawg0cOpuRSFoltsWEWJP/ggw8yloKpqakx5557rt03n3POOcfMmDGjhHdRVALjxo2zZf+w5e23396W0cKusGXsjIw2Zjlsttlm5uGHH7Z/w3cDBw407777rrWpbGBjxx57rFlkkUXm+4799O7d29rqLrvsYt57772iXacoL7R32MrLL79s7Quboq2iz+XZ054dfvjhtsQQ0He77WhTv/jii3Q//Pjjj9sP38PXX39t14RiW9rRffbZx3zzzTcFnSc2vs0225g111zTtosXXHCBqa2tTbevzIw74YQT7PvSp08f8+mnn5prr73WtvWbbrppnbIKYf2EqExko7LRJCA7lZ0KIeYiYV1UPJ988omtiUqwmwlERTrw9dZbzwbWThz68ccf64g4b7zxhvm///s/M336dNsJduvWzTz55JNW1Lzpppvq1Gd97rnnTIsWLWwHT6dOME95DyHCkJ2KcvD333/boGWTTTaxpYcQIrEpZk044RubQPBGrCZbF7GcQOXMM880HTt2tCVZllhiCbs99kVQQZkYApBTTz21ThYRg0Lsi8EfApwDDjjA2jSiJIIl66I8//zz6e0JosgOxkbZ7rDDDjOTJk2a7zrOPvtsG6xg45Tq4P+vu+66ktxDURnQfmLLbdq0sWVdsBUEc8fHH39sPvvsMzNkyBBzzDHH2MAY28VeDzroIGvT/BwG+2SwZo899pjvO+z3oosussfnHdh4443t8WmjRcOFdpI2h2d/3333WbtiwJp2dPTo0eaRRx4xL730krVD2k/aMfrk/fff3/z555/W7hiM4cO2lHtjIJGZa0888YRt/xBvEG2igp+AQHXSSSeZ4cOHW3vnGC+++GJ6m3vuuccO1uMjtG3b1rbH1CnmHUGcYuCdc8rVT4jKRTYqG00CslPZqRDVjoR1kYhMYFhwwQUzfr/wwgvbf1dfffV09uP7779vO71ffvnFTJw40Xba1FRFsHzqqafMoosuakeml19+edth0nkjODnoVBEyl1tuOZu9yc9jx44tyfWKZCI7FeWAAZijjjrK1vKn7BCBCrMgvvrqK/s9gQiBzoorrmgXbOzUqZMVKJs3b25at25tZ1dQksXNsiBLnSyjZZdd1g7sTJgwwQYXjj333NPuC7GchU/XWGMNG6zwu5133tn07dvX/O9/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IYQQQgghhBBCiAhIWBdCCCFCeOedd8xqq61WtP2zb45RKE8++aTZeuutTdeuXc1ee+1lxowZk3X7559/3h7T/xx33HEmaYwbN84uahnGgAEDzH777ZfXvmbOnGkeeuihWM7rs88+Mx988EEs+xKioZKt3Yvy7hab2tpac9VVV5lNNtnErLPOOub44483EydOzKtN2W677XK27Uwa5no33XRTs95665kTTjjBTJo0Kf19sK3ecMMNzdlnn23++eefrPvdYostzGOPPWbiWFB42LBhphhMnTrVDB061FQqDdVGx48fb/v89ddf3y4Ufdlll5kZM2YUvH9szbfR7t272/1jO9ng/nEfK9mO4vQN4qKh2uUPP/xgDj74YLvtZpttZhcuz0awbXQfZwvY9JlnnmntsUePHubOO++cz693nzXWWMPaca5j/vTTT3Z7/q1kXzGXfyyEKA4S1qsEHJyLL77YbL755mattdYy2267rbnjjjvM7NmzS3oeBBG33Xab7cDWXXddc8ABB5ivv/46FhHIdXiZPu+9957d5ptvvjEHHXSQPTbncMstt5g5c+bY7whC/L/p3LmzrfOay2GLU3h766237DkWgzg78WqwJwf2wQJ6O+ywg71WrplrnzJlSsHnja1xznHy8ccfW2GVc0RoDdrtyy+/bHbccUfrtG6//fbmxRdfTH93+umn17kn7CMfkTYuJ57nOHjwYFMsEAZyBXlJ5P3337d1qI866ijzzDPP2Gd76KGHZhVdeD+w4ddffz39wZ6TBgFTLvvMF+4dfUEcHH300eb777+PZV9CiPKCf/Hss8/a2v8PP/yw+fPPP82pp56a9W8QdE466STz1Vdf5dz/kCFDzCOPPGIFKPrA33//3bbpwX6WdvrVV1+17RTtXv/+/U0p4LyKJdDcfffd5tFHHy3KvquJKDaKr4XPO23aNGtv1157rRk5cqT92/rsn/7Y2eh9991ntznttNNMKSimHcXpG1QbUeySOOuwww4z7dq1M48//ri54IILzM0332yeeuqp0P37PiyfQw45xCy11FJmyy23tN/TRo4dO9bGb+edd54ZOHCgGT58eMZ9vPDCC9aGb7rpJnvOpaCYvmKc/rEQIn8krFcBZCfsvvvu5rvvvjNXXnmlefrpp22DjlN15JFHpoXlUvDggw/aUeNzzjnHOkJLL720FYJw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9dapK664ItWzZ8/UQQcdlBo/fnyqpqYmteaaa6auu+669N/16tUrdeyxx9bZ19ixY1P77LOP3bZHjx52+9raWvvdDTfckOrbt2+d7TfffPPUo48+mvr9999Tq666asYP38Npp51W5++//PLLVL9+/VJrr712apNNNkkNGDAgNWfOnKzXevDBB6euuuqq+X5/zjnnZDw25wecg//7Tp06pTbccMPU2Wefnfrjjz9Cj/f222/b7YPXG/b90KFD7X3l/vHv008/nf7u6quvts/nkksusftw5+aYPHly6ogjjrDb8OxGjhxp9z1u3Dj7Pc/xqKOOSq211lr2fvE83P0aNGiQvY9HH310qr5Ukz1Nnz7dngfnzrVyfJ7PlClT0tvMnj07dc0116Q23njjVNeuXVMHHHBA6osvvkh/P2nSJHvfeS69e/e2x/WfbdR7kImvv/7aHpdrY98PPfRQ+jueT6b7xP1x98n//RprrJHaYostUjfddJO9tjD8c8MGfVsMfs/19O/f3953rnOvvfZKffLJJ/a7GTNmpA488MBU586dU88995w9H3duDrbdeeed7Tb87ZAhQ+rcww8++CC122672e+32WYbux/HKaecYn9/11135byPQgghhBBCCCGEEPnQiP/EKdSLZEGmMYvRMUIcXDBPiKjInoQQQgghhBBCCCFENSBhXQghhBBCCCGEEEIIIYSIgGqsCyGEEEIIIYQQQgghhBARkLAuhBBCCCGEEEIIIYQQQkRAwroQQgghhBBCCCGEEEIIEQEJ60IIIYQQQgghhBBCCCFEBCSsCyGEEEIIIYQQQgghhBARkLAuhBBCCCGEEEIIIYQQQkRAwroQQgghhBBCCCGEEEIIEQEJ60IIIYQQQgghhBBCCCFEBCSsCyGEEEIIIYQQQgghhBARkLAuhBBCCCGEEEIIIYQQQpj8+X9tyqVsNBlimgAAAABJRU5ErkJggg==",
+ "image/png": "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9bPPPnvsd2eddVYu+7Lemnq8QRAEQRAEQRAEQRAEQRAEQTDdDG2EeuHChelRj3pUevOb35zOPffc9L3vfS996lOfSvvtt99M31oQBEEQBEEQBEEQBEEQBEGwDjO0NdaxdOnSHFg/+eST06JFi9KznvWs9PSnP32mbysIgiAIgiAIgiAIgiAIgiBYhxnajPWStf6e97wn/epXv0qnn356BNVnKf/973/zi2rvf//7pzvf+c7poQ99aPrkJz+Z6+sHQT+ELAVTgZdjf/nLXx77+alPfWo69NBDp+36t7/97fNLu4N1h6uvvjodf/zxPR1Lvz3ykY+cVpkMhmO+O/HEEyf89695zWvyB2SHXgvWTUKWgkES8hQMkloe+rHV++W4445LD3jAA3o6NuQyCIKRCqwHs59///vf6fGPf3z661//mt73vvelb33rW+kFL3hBOvroo9MBBxyQVq5cOdO3GIwIIUvBVPHtb387HXHEETN2/R/96Edpl112mbHrB9PPZz7zmfTVr361p2OVyTvvvPOm/J6C4eL9739/Ou2002b6NoJZQMhSMEhCnoJBctBBB+XPMNnqz3zmMyOZIQiCccwb/2MQTC/vfOc7001vetP08Y9/PM2dOzf/btttt00777xzzjb+4he/mPbZZ5+Zvs1gBAhZCqaKma6YtuWWW87o9YPhlbm///3v6XOf+1y6zW1uM+X3FAwXM62XgtlDyFIwSEKegkGy8cYbD53cbbTRRtN2rSAIRoPIWA9mjMsvvzy/lPbZz372WCC0sM0226THPvax6Utf+lLafffd06mnnjr23YMe9KD06le/euznD37wg+kVr3hF/vcf//jHvDXrTne6U3rwgx+cs5ULVpZf/vKXpze96U3pLne5S7rHPe6RjjzyyGl51mBqCVkKeuGss85KT37yk3OZIAsu5OU///lP3v6prz/84Q+nu93tbmm33XZL73rXu7KRrgTLa1/72vTPf/4zl2S58MILx3ZI7L///mmnnXbK8vHjH/947DqOO+SQQ/K5nve85+XfKWnm2q5rq6mFnoItrkoYOZa8eXH3L3/5y5alYJYsWZLe+MY35nP7vOENb0jXXXfdNLZi0A8XXHBBLmNH5h7+8Ifn0lT6n8yRB5l9diPc7373S8cee2z+G98ddthh6ec//3nu+06QhRe+8IVp8803X+s759lr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",
"text/plain": [
""
]
@@ -995,7 +1171,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "compare-agents",
+ "display_name": "test",
"language": "python",
"name": "python3"
},
diff --git a/src/smolagents/agents.py b/src/smolagents/agents.py
index e9c3d9d14..832ac8efc 100644
--- a/src/smolagents/agents.py
+++ b/src/smolagents/agents.py
@@ -884,7 +884,6 @@ def __init__(
system_prompt: Optional[str] = None,
grammar: Optional[Dict[str, str]] = None,
additional_authorized_imports: Optional[List[str]] = None,
- allow_all_imports: bool = False,
planning_interval: Optional[int] = None,
use_e2b_executor: bool = False,
**kwargs,
@@ -899,18 +898,29 @@ def __init__(
planning_interval=planning_interval,
**kwargs,
)
-
- if ( allow_all_imports and
- ( not(additional_authorized_imports is None) and (len(additional_authorized_imports)) > 0)):
- raise Exception(
- f"You passed both allow_all_imports and additional_authorized_imports. Please choose one."
- )
-
- if allow_all_imports: additional_authorized_imports=['*']
-
self.additional_authorized_imports = (
additional_authorized_imports if additional_authorized_imports else []
)
+ self.authorized_imports = list(
+ set(BASE_BUILTIN_MODULES) | set(self.additional_authorized_imports)
+ )
+ if "{{authorized_imports}}" not in self.system_prompt:
+ raise AgentError(
+ "Tag '{{authorized_imports}}' should be provided in the prompt."
+ )
+ self.system_prompt = self.system_prompt.replace(
+ "{{authorized_imports}}",
+ "You can import from any package you want."
+ if "*" in self.authorized_imports
+ else str(self.authorized_imports),
+ )
+
+ if "*" in self.additional_authorized_imports:
+ self.logger.log(
+ "Caution: you set an authorization for all imports, meaning your agent can decide to import any package it deems necessary. This might raise issues if the package is not installed in your environment.",
+ 0,
+ )
+
if use_e2b_executor and len(self.managed_agents) > 0:
raise Exception(
f"You passed both {use_e2b_executor=} and some managed agents. Managed agents is not yet supported with remote code execution."
@@ -919,25 +929,15 @@ def __init__(
all_tools = {**self.tools, **self.managed_agents}
if use_e2b_executor:
self.python_executor = E2BExecutor(
- self.additional_authorized_imports, list(all_tools.values())
+ self.additional_authorized_imports,
+ list(all_tools.values()),
+ self.logger,
)
else:
self.python_executor = LocalPythonInterpreter(
- self.additional_authorized_imports, all_tools
+ self.additional_authorized_imports,
+ all_tools,
)
- if allow_all_imports:
- self.authorized_imports = 'all imports without restriction'
- else:
- self.authorized_imports = list(
- set(BASE_BUILTIN_MODULES) | set(self.additional_authorized_imports)
- )
- if "{{authorized_imports}}" not in self.system_prompt:
- raise AgentError(
- "Tag '{{authorized_imports}}' should be provided in the prompt."
- )
- self.system_prompt = self.system_prompt.replace(
- "{{authorized_imports}}", str(self.authorized_imports)
- )
def step(self, log_entry: ActionStep) -> Union[None, Any]:
"""
diff --git a/src/smolagents/e2b_executor.py b/src/smolagents/e2b_executor.py
index 68f557940..e8cc89347 100644
--- a/src/smolagents/e2b_executor.py
+++ b/src/smolagents/e2b_executor.py
@@ -26,13 +26,13 @@
from .tool_validation import validate_tool_attributes
from .tools import Tool
-from .utils import BASE_BUILTIN_MODULES, console, instance_to_source
+from .utils import BASE_BUILTIN_MODULES, instance_to_source
load_dotenv()
class E2BExecutor:
- def __init__(self, additional_imports: List[str], tools: List[Tool]):
+ def __init__(self, additional_imports: List[str], tools: List[Tool], logger):
self.custom_tools = {}
self.sbx = Sandbox() # "qywp2ctmu2q7jzprcf4j")
# TODO: validate installing agents package or not
@@ -42,6 +42,7 @@ def __init__(self, additional_imports: List[str], tools: List[Tool]):
# timeout=300
# )
# print("Installation of agents package finished.")
+ self.logger = logger
additional_imports = additional_imports + ["pickle5"]
if len(additional_imports) > 0:
execution = self.sbx.commands.run(
@@ -50,7 +51,7 @@ def __init__(self, additional_imports: List[str], tools: List[Tool]):
if execution.error:
raise Exception(f"Error installing dependencies: {execution.error}")
else:
- console.print(f"Installation of {additional_imports} succeeded!")
+ logger.log(f"Installation of {additional_imports} succeeded!", 0)
tool_codes = []
for tool in tools:
@@ -74,7 +75,7 @@ def forward(self, *args, **kwargs):
tool_definition_code += "\n\n".join(tool_codes)
tool_definition_execution = self.run_code_raise_errors(tool_definition_code)
- console.print(tool_definition_execution.logs)
+ self.logger.log(tool_definition_execution.logs)
def run_code_raise_errors(self, code: str):
execution = self.sbx.run_code(
@@ -109,7 +110,7 @@ def __call__(self, code_action: str, additional_args: dict) -> Tuple[Any, Any]:
"""
execution = self.run_code_raise_errors(remote_unloading_code)
execution_logs = "\n".join([str(log) for log in execution.logs.stdout])
- console.print(execution_logs)
+ self.logger.log(execution_logs, 1)
execution = self.run_code_raise_errors(code_action)
execution_logs = "\n".join([str(log) for log in execution.logs.stdout])
diff --git a/src/smolagents/gradio_ui.py b/src/smolagents/gradio_ui.py
index 514bd1f22..45ae8a250 100644
--- a/src/smolagents/gradio_ui.py
+++ b/src/smolagents/gradio_ui.py
@@ -85,7 +85,7 @@ def stream_to_gradio(
class GradioUI:
"""A one-line interface to launch your agent in Gradio"""
- def __init__(self, agent: MultiStepAgent, file_upload_folder: str | None=None):
+ def __init__(self, agent: MultiStepAgent, file_upload_folder: str | None = None):
self.agent = agent
self.file_upload_folder = file_upload_folder
if self.file_upload_folder is not None:
@@ -100,7 +100,15 @@ def interact_with_agent(self, prompt, messages):
yield messages
yield messages
- def upload_file(self, file, allowed_file_types=["application/pdf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "text/plain"]):
+ def upload_file(
+ self,
+ file,
+ allowed_file_types=[
+ "application/pdf",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "text/plain",
+ ],
+ ):
"""
Handle file uploads, default allowed types are pdf, docx, and .txt
"""
@@ -110,18 +118,19 @@ def upload_file(self, file, allowed_file_types=["application/pdf", "application/
return "No file uploaded"
# Check if file is in allowed filetypes
- name = os.path.basename(file.name)
try:
mime_type, _ = mimetypes.guess_type(file.name)
except Exception as e:
return f"Error: {e}"
-
+
if mime_type not in allowed_file_types:
return "File type disallowed"
-
+
# Sanitize file name
original_name = os.path.basename(file.name)
- sanitized_name = re.sub(r'[^\w\-.]', '_', original_name) # Replace any non-alphanumeric, non-dash, or non-dot characters with underscores
+ sanitized_name = re.sub(
+ r"[^\w\-.]", "_", original_name
+ ) # Replace any non-alphanumeric, non-dash, or non-dot characters with underscores
type_to_ext = {}
for ext, t in mimetypes.types_map.items():
@@ -134,7 +143,9 @@ def upload_file(self, file, allowed_file_types=["application/pdf", "application/
sanitized_name = "".join(sanitized_name)
# Save the uploaded file to the specified folder
- file_path = os.path.join(self.file_upload_folder, os.path.basename(sanitized_name))
+ file_path = os.path.join(
+ self.file_upload_folder, os.path.basename(sanitized_name)
+ )
shutil.copy(file.name, file_path)
return f"File uploaded successfully to {self.file_upload_folder}"
@@ -155,9 +166,7 @@ def launch(self):
upload_file = gr.File(label="Upload a file")
upload_status = gr.Textbox(label="Upload Status", interactive=False)
- upload_file.change(
- self.upload_file, [upload_file], [upload_status]
- )
+ upload_file.change(self.upload_file, [upload_file], [upload_status])
text_input = gr.Textbox(lines=1, label="Chat Message")
text_input.submit(
lambda s: (s, ""), [text_input], [stored_message, text_input]
diff --git a/src/smolagents/local_python_executor.py b/src/smolagents/local_python_executor.py
index a70b53766..3c545cae6 100644
--- a/src/smolagents/local_python_executor.py
+++ b/src/smolagents/local_python_executor.py
@@ -159,8 +159,16 @@ def fix_final_answer_code(code: str) -> str:
return code
-def evaluate_unaryop(expression, state, static_tools, custom_tools):
- operand = evaluate_ast(expression.operand, state, static_tools, custom_tools)
+def evaluate_unaryop(
+ expression: ast.UnaryOp,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
+ operand = evaluate_ast(
+ expression.operand, state, static_tools, custom_tools, authorized_imports
+ )
if isinstance(expression.op, ast.USub):
return -operand
elif isinstance(expression.op, ast.UAdd):
@@ -175,27 +183,47 @@ def evaluate_unaryop(expression, state, static_tools, custom_tools):
)
-def evaluate_lambda(lambda_expression, state, static_tools, custom_tools):
+def evaluate_lambda(
+ lambda_expression: ast.Lambda,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Callable:
args = [arg.arg for arg in lambda_expression.args.args]
- def lambda_func(*values):
+ def lambda_func(*values: Any) -> Any:
new_state = state.copy()
for arg, value in zip(args, values):
new_state[arg] = value
return evaluate_ast(
- lambda_expression.body, new_state, static_tools, custom_tools
+ lambda_expression.body,
+ new_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
)
return lambda_func
-def evaluate_while(while_loop, state, static_tools, custom_tools):
+def evaluate_while(
+ while_loop: ast.While,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
max_iterations = 1000
iterations = 0
- while evaluate_ast(while_loop.test, state, static_tools, custom_tools):
+ while evaluate_ast(
+ while_loop.test, state, static_tools, custom_tools, authorized_imports
+ ):
for node in while_loop.body:
try:
- evaluate_ast(node, state, static_tools, custom_tools)
+ evaluate_ast(
+ node, state, static_tools, custom_tools, authorized_imports
+ )
except BreakException:
return None
except ContinueException:
@@ -208,12 +236,18 @@ def evaluate_while(while_loop, state, static_tools, custom_tools):
return None
-def create_function(func_def, state, static_tools, custom_tools):
- def new_func(*args, **kwargs):
+def create_function(
+ func_def: ast.FunctionDef,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Callable:
+ def new_func(*args: Any, **kwargs: Any) -> Any:
func_state = state.copy()
arg_names = [arg.arg for arg in func_def.args.args]
default_values = [
- evaluate_ast(d, state, static_tools, custom_tools)
+ evaluate_ast(d, state, static_tools, custom_tools, authorized_imports)
for d in func_def.args.defaults
]
@@ -224,7 +258,7 @@ def new_func(*args, **kwargs):
for name, value in zip(arg_names, args):
func_state[name] = value
- # # Set keyword arguments
+ # Set keyword arguments
for name, value in kwargs.items():
func_state[name] = value
@@ -251,7 +285,9 @@ def new_func(*args, **kwargs):
result = None
try:
for stmt in func_def.body:
- result = evaluate_ast(stmt, func_state, static_tools, custom_tools)
+ result = evaluate_ast(
+ stmt, func_state, static_tools, custom_tools, authorized_imports
+ )
except ReturnException as e:
result = e.value
@@ -263,24 +299,29 @@ def new_func(*args, **kwargs):
return new_func
-def create_class(class_name, class_bases, class_body):
- class_dict = {}
- for key, value in class_body.items():
- class_dict[key] = value
- return type(class_name, tuple(class_bases), class_dict)
-
-
-def evaluate_function_def(func_def, state, static_tools, custom_tools):
+def evaluate_function_def(
+ func_def: ast.FunctionDef,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Callable:
custom_tools[func_def.name] = create_function(
- func_def, state, static_tools, custom_tools
+ func_def, state, static_tools, custom_tools, authorized_imports
)
return custom_tools[func_def.name]
-def evaluate_class_def(class_def, state, static_tools, custom_tools):
+def evaluate_class_def(
+ class_def: ast.ClassDef,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> type:
class_name = class_def.name
bases = [
- evaluate_ast(base, state, static_tools, custom_tools)
+ evaluate_ast(base, state, static_tools, custom_tools, authorized_imports)
for base in class_def.bases
]
class_dict = {}
@@ -288,17 +329,25 @@ def evaluate_class_def(class_def, state, static_tools, custom_tools):
for stmt in class_def.body:
if isinstance(stmt, ast.FunctionDef):
class_dict[stmt.name] = evaluate_function_def(
- stmt, state, static_tools, custom_tools
+ stmt, state, static_tools, custom_tools, authorized_imports
)
elif isinstance(stmt, ast.Assign):
for target in stmt.targets:
if isinstance(target, ast.Name):
class_dict[target.id] = evaluate_ast(
- stmt.value, state, static_tools, custom_tools
+ stmt.value,
+ state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
)
elif isinstance(target, ast.Attribute):
class_dict[target.attr] = evaluate_ast(
- stmt.value, state, static_tools, custom_tools
+ stmt.value,
+ state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
)
else:
raise InterpreterError(
@@ -310,16 +359,28 @@ def evaluate_class_def(class_def, state, static_tools, custom_tools):
return new_class
-def evaluate_augassign(expression, state, static_tools, custom_tools):
- def get_current_value(target):
+def evaluate_augassign(
+ expression: ast.AugAssign,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
+ def get_current_value(target: ast.AST) -> Any:
if isinstance(target, ast.Name):
return state.get(target.id, 0)
elif isinstance(target, ast.Subscript):
- obj = evaluate_ast(target.value, state, static_tools, custom_tools)
- key = evaluate_ast(target.slice, state, static_tools, custom_tools)
+ obj = evaluate_ast(
+ target.value, state, static_tools, custom_tools, authorized_imports
+ )
+ key = evaluate_ast(
+ target.slice, state, static_tools, custom_tools, authorized_imports
+ )
return obj[key]
elif isinstance(target, ast.Attribute):
- obj = evaluate_ast(target.value, state, static_tools, custom_tools)
+ obj = evaluate_ast(
+ target.value, state, static_tools, custom_tools, authorized_imports
+ )
return getattr(obj, target.attr)
elif isinstance(target, ast.Tuple):
return tuple(get_current_value(elt) for elt in target.elts)
@@ -331,7 +392,9 @@ def get_current_value(target):
)
current_value = get_current_value(expression.target)
- value_to_add = evaluate_ast(expression.value, state, static_tools, custom_tools)
+ value_to_add = evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
if isinstance(expression.op, ast.Add):
if isinstance(current_value, list):
@@ -370,28 +433,55 @@ def get_current_value(target):
)
# Update the state
- set_value(expression.target, updated_value, state, static_tools, custom_tools)
+ set_value(
+ expression.target,
+ updated_value,
+ state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
+ )
return updated_value
-def evaluate_boolop(node, state, static_tools, custom_tools):
+def evaluate_boolop(
+ node: ast.BoolOp,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> bool:
if isinstance(node.op, ast.And):
for value in node.values:
- if not evaluate_ast(value, state, static_tools, custom_tools):
+ if not evaluate_ast(
+ value, state, static_tools, custom_tools, authorized_imports
+ ):
return False
return True
elif isinstance(node.op, ast.Or):
for value in node.values:
- if evaluate_ast(value, state, static_tools, custom_tools):
+ if evaluate_ast(
+ value, state, static_tools, custom_tools, authorized_imports
+ ):
return True
return False
-def evaluate_binop(binop, state, static_tools, custom_tools):
+def evaluate_binop(
+ binop: ast.BinOp,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
# Recursively evaluate the left and right operands
- left_val = evaluate_ast(binop.left, state, static_tools, custom_tools)
- right_val = evaluate_ast(binop.right, state, static_tools, custom_tools)
+ left_val = evaluate_ast(
+ binop.left, state, static_tools, custom_tools, authorized_imports
+ )
+ right_val = evaluate_ast(
+ binop.right, state, static_tools, custom_tools, authorized_imports
+ )
# Determine the operation based on the type of the operator in the BinOp
if isinstance(binop.op, ast.Add):
@@ -424,11 +514,19 @@ def evaluate_binop(binop, state, static_tools, custom_tools):
)
-def evaluate_assign(assign, state, static_tools, custom_tools):
- result = evaluate_ast(assign.value, state, static_tools, custom_tools)
+def evaluate_assign(
+ assign: ast.Assign,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
+ result = evaluate_ast(
+ assign.value, state, static_tools, custom_tools, authorized_imports
+ )
if len(assign.targets) == 1:
target = assign.targets[0]
- set_value(target, result, state, static_tools, custom_tools)
+ set_value(target, result, state, static_tools, custom_tools, authorized_imports)
else:
if len(assign.targets) != len(result):
raise InterpreterError(
@@ -441,11 +539,18 @@ def evaluate_assign(assign, state, static_tools, custom_tools):
else:
expanded_values.append(result)
for tgt, val in zip(assign.targets, expanded_values):
- set_value(tgt, val, state, static_tools, custom_tools)
+ set_value(tgt, val, state, static_tools, custom_tools, authorized_imports)
return result
-def set_value(target, value, state, static_tools, custom_tools):
+def set_value(
+ target: ast.AST,
+ value: Any,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
if isinstance(target, ast.Name):
if target.id in static_tools:
raise InterpreterError(
@@ -461,21 +566,37 @@ def set_value(target, value, state, static_tools, custom_tools):
if len(target.elts) != len(value):
raise InterpreterError("Cannot unpack tuple of wrong size")
for i, elem in enumerate(target.elts):
- set_value(elem, value[i], state, static_tools, custom_tools)
+ set_value(
+ elem, value[i], state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(target, ast.Subscript):
- obj = evaluate_ast(target.value, state, static_tools, custom_tools)
- key = evaluate_ast(target.slice, state, static_tools, custom_tools)
+ obj = evaluate_ast(
+ target.value, state, static_tools, custom_tools, authorized_imports
+ )
+ key = evaluate_ast(
+ target.slice, state, static_tools, custom_tools, authorized_imports
+ )
obj[key] = value
elif isinstance(target, ast.Attribute):
- obj = evaluate_ast(target.value, state, static_tools, custom_tools)
+ obj = evaluate_ast(
+ target.value, state, static_tools, custom_tools, authorized_imports
+ )
setattr(obj, target.attr, value)
-def evaluate_call(call, state, static_tools, custom_tools):
+def evaluate_call(
+ call: ast.Call,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
if not (isinstance(call.func, ast.Attribute) or isinstance(call.func, ast.Name)):
raise InterpreterError(f"This is not a correct function: {call.func}).")
if isinstance(call.func, ast.Attribute):
- obj = evaluate_ast(call.func.value, state, static_tools, custom_tools)
+ obj = evaluate_ast(
+ call.func.value, state, static_tools, custom_tools, authorized_imports
+ )
func_name = call.func.attr
if not hasattr(obj, func_name):
raise InterpreterError(f"Object {obj} has no attribute {func_name}")
@@ -499,22 +620,20 @@ def evaluate_call(call, state, static_tools, custom_tools):
args = []
for arg in call.args:
if isinstance(arg, ast.Starred):
- args.extend(evaluate_ast(arg.value, state, static_tools, custom_tools))
- else:
- args.append(evaluate_ast(arg, state, static_tools, custom_tools))
-
- args = []
- for arg in call.args:
- if isinstance(arg, ast.Starred):
- unpacked = evaluate_ast(arg.value, state, static_tools, custom_tools)
- if not hasattr(unpacked, "__iter__") or isinstance(unpacked, (str, bytes)):
- raise InterpreterError(f"Cannot unpack non-iterable value {unpacked}")
- args.extend(unpacked)
+ args.extend(
+ evaluate_ast(
+ arg.value, state, static_tools, custom_tools, authorized_imports
+ )
+ )
else:
- args.append(evaluate_ast(arg, state, static_tools, custom_tools))
+ args.append(
+ evaluate_ast(arg, state, static_tools, custom_tools, authorized_imports)
+ )
kwargs = {
- keyword.arg: evaluate_ast(keyword.value, state, static_tools, custom_tools)
+ keyword.arg: evaluate_ast(
+ keyword.value, state, static_tools, custom_tools, authorized_imports
+ )
for keyword in call.keywords
}
@@ -545,9 +664,19 @@ def evaluate_call(call, state, static_tools, custom_tools):
return func(*args, **kwargs)
-def evaluate_subscript(subscript, state, static_tools, custom_tools):
- index = evaluate_ast(subscript.slice, state, static_tools, custom_tools)
- value = evaluate_ast(subscript.value, state, static_tools, custom_tools)
+def evaluate_subscript(
+ subscript: ast.Subscript,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
+ index = evaluate_ast(
+ subscript.slice, state, static_tools, custom_tools, authorized_imports
+ )
+ value = evaluate_ast(
+ subscript.value, state, static_tools, custom_tools, authorized_imports
+ )
if isinstance(value, str) and isinstance(index, str):
raise InterpreterError(
@@ -583,7 +712,13 @@ def evaluate_subscript(subscript, state, static_tools, custom_tools):
raise InterpreterError(f"Could not index {value} with '{index}'.")
-def evaluate_name(name, state, static_tools, custom_tools):
+def evaluate_name(
+ name: ast.Name,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
if name.id in state:
return state[name.id]
elif name.id in static_tools:
@@ -596,10 +731,18 @@ def evaluate_name(name, state, static_tools, custom_tools):
raise InterpreterError(f"The variable `{name.id}` is not defined.")
-def evaluate_condition(condition, state, static_tools, custom_tools):
- left = evaluate_ast(condition.left, state, static_tools, custom_tools)
+def evaluate_condition(
+ condition: ast.Compare,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> bool:
+ left = evaluate_ast(
+ condition.left, state, static_tools, custom_tools, authorized_imports
+ )
comparators = [
- evaluate_ast(c, state, static_tools, custom_tools)
+ evaluate_ast(c, state, static_tools, custom_tools, authorized_imports)
for c in condition.comparators
]
ops = [type(op) for op in condition.ops]
@@ -640,30 +783,59 @@ def evaluate_condition(condition, state, static_tools, custom_tools):
return result if isinstance(result, (bool, pd.Series)) else result.all()
-def evaluate_if(if_statement, state, static_tools, custom_tools):
+def evaluate_if(
+ if_statement: ast.If,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
result = None
- test_result = evaluate_ast(if_statement.test, state, static_tools, custom_tools)
+ test_result = evaluate_ast(
+ if_statement.test, state, static_tools, custom_tools, authorized_imports
+ )
if test_result:
for line in if_statement.body:
- line_result = evaluate_ast(line, state, static_tools, custom_tools)
+ line_result = evaluate_ast(
+ line, state, static_tools, custom_tools, authorized_imports
+ )
if line_result is not None:
result = line_result
else:
for line in if_statement.orelse:
- line_result = evaluate_ast(line, state, static_tools, custom_tools)
+ line_result = evaluate_ast(
+ line, state, static_tools, custom_tools, authorized_imports
+ )
if line_result is not None:
result = line_result
return result
-def evaluate_for(for_loop, state, static_tools, custom_tools):
+def evaluate_for(
+ for_loop: ast.For,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Any:
result = None
- iterator = evaluate_ast(for_loop.iter, state, static_tools, custom_tools)
+ iterator = evaluate_ast(
+ for_loop.iter, state, static_tools, custom_tools, authorized_imports
+ )
for counter in iterator:
- set_value(for_loop.target, counter, state, static_tools, custom_tools)
+ set_value(
+ for_loop.target,
+ counter,
+ state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
+ )
for node in for_loop.body:
try:
- line_result = evaluate_ast(node, state, static_tools, custom_tools)
+ line_result = evaluate_ast(
+ node, state, static_tools, custom_tools, authorized_imports
+ )
if line_result is not None:
result = line_result
except BreakException:
@@ -676,15 +848,33 @@ def evaluate_for(for_loop, state, static_tools, custom_tools):
return result
-def evaluate_listcomp(listcomp, state, static_tools, custom_tools):
- def inner_evaluate(generators, index, current_state):
+def evaluate_listcomp(
+ listcomp: ast.ListComp,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> List[Any]:
+ def inner_evaluate(
+ generators: List[ast.comprehension], index: int, current_state: Dict[str, Any]
+ ) -> List[Any]:
if index >= len(generators):
return [
- evaluate_ast(listcomp.elt, current_state, static_tools, custom_tools)
+ evaluate_ast(
+ listcomp.elt,
+ current_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
+ )
]
generator = generators[index]
iter_value = evaluate_ast(
- generator.iter, current_state, static_tools, custom_tools
+ generator.iter,
+ current_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
)
result = []
for value in iter_value:
@@ -695,7 +885,9 @@ def inner_evaluate(generators, index, current_state):
else:
new_state[generator.target.id] = value
if all(
- evaluate_ast(if_clause, new_state, static_tools, custom_tools)
+ evaluate_ast(
+ if_clause, new_state, static_tools, custom_tools, authorized_imports
+ )
for if_clause in generator.ifs
):
result.extend(inner_evaluate(generators, index + 1, new_state))
@@ -704,41 +896,66 @@ def inner_evaluate(generators, index, current_state):
return inner_evaluate(listcomp.generators, 0, state)
-def evaluate_try(try_node, state, static_tools, custom_tools):
+def evaluate_try(
+ try_node: ast.Try,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
try:
for stmt in try_node.body:
- evaluate_ast(stmt, state, static_tools, custom_tools)
+ evaluate_ast(stmt, state, static_tools, custom_tools, authorized_imports)
except Exception as e:
matched = False
for handler in try_node.handlers:
if handler.type is None or isinstance(
- e, evaluate_ast(handler.type, state, static_tools, custom_tools)
+ e,
+ evaluate_ast(
+ handler.type, state, static_tools, custom_tools, authorized_imports
+ ),
):
matched = True
if handler.name:
state[handler.name] = e
for stmt in handler.body:
- evaluate_ast(stmt, state, static_tools, custom_tools)
+ evaluate_ast(
+ stmt, state, static_tools, custom_tools, authorized_imports
+ )
break
if not matched:
raise e
else:
if try_node.orelse:
for stmt in try_node.orelse:
- evaluate_ast(stmt, state, static_tools, custom_tools)
+ evaluate_ast(
+ stmt, state, static_tools, custom_tools, authorized_imports
+ )
finally:
if try_node.finalbody:
for stmt in try_node.finalbody:
- evaluate_ast(stmt, state, static_tools, custom_tools)
+ evaluate_ast(
+ stmt, state, static_tools, custom_tools, authorized_imports
+ )
-def evaluate_raise(raise_node, state, static_tools, custom_tools):
+def evaluate_raise(
+ raise_node: ast.Raise,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
if raise_node.exc is not None:
- exc = evaluate_ast(raise_node.exc, state, static_tools, custom_tools)
+ exc = evaluate_ast(
+ raise_node.exc, state, static_tools, custom_tools, authorized_imports
+ )
else:
exc = None
if raise_node.cause is not None:
- cause = evaluate_ast(raise_node.cause, state, static_tools, custom_tools)
+ cause = evaluate_ast(
+ raise_node.cause, state, static_tools, custom_tools, authorized_imports
+ )
else:
cause = None
if exc is not None:
@@ -750,11 +967,21 @@ def evaluate_raise(raise_node, state, static_tools, custom_tools):
raise InterpreterError("Re-raise is not supported without an active exception")
-def evaluate_assert(assert_node, state, static_tools, custom_tools):
- test_result = evaluate_ast(assert_node.test, state, static_tools, custom_tools)
+def evaluate_assert(
+ assert_node: ast.Assert,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
+ test_result = evaluate_ast(
+ assert_node.test, state, static_tools, custom_tools, authorized_imports
+ )
if not test_result:
if assert_node.msg:
- msg = evaluate_ast(assert_node.msg, state, static_tools, custom_tools)
+ msg = evaluate_ast(
+ assert_node.msg, state, static_tools, custom_tools, authorized_imports
+ )
raise AssertionError(msg)
else:
# Include the failing condition in the assertion message
@@ -762,11 +989,17 @@ def evaluate_assert(assert_node, state, static_tools, custom_tools):
raise AssertionError(f"Assertion failed: {test_code}")
-def evaluate_with(with_node, state, static_tools, custom_tools):
+def evaluate_with(
+ with_node: ast.With,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> None:
contexts = []
for item in with_node.items:
context_expr = evaluate_ast(
- item.context_expr, state, static_tools, custom_tools
+ item.context_expr, state, static_tools, custom_tools, authorized_imports
)
if item.optional_vars:
state[item.optional_vars.id] = context_expr.__enter__()
@@ -777,7 +1010,7 @@ def evaluate_with(with_node, state, static_tools, custom_tools):
try:
for stmt in with_node.body:
- evaluate_ast(stmt, state, static_tools, custom_tools)
+ evaluate_ast(stmt, state, static_tools, custom_tools, authorized_imports)
except Exception as e:
for context in reversed(contexts):
context.__exit__(type(e), e, e.__traceback__)
@@ -789,15 +1022,14 @@ def evaluate_with(with_node, state, static_tools, custom_tools):
def import_modules(expression, state, authorized_imports):
def check_module_authorized(module_name):
- if '*' in authorized_imports:
- return True
- else:
- module_path = module_name.split(".")
- module_subpaths = [
- ".".join(module_path[:i]) for i in range(1, len(module_path) + 1)
- ]
- return any(subpath in authorized_imports for subpath in module_subpaths)
-
+ if "*" in authorized_imports:
+ return True
+ else:
+ module_path = module_name.split(".")
+ module_subpaths = [
+ ".".join(module_path[:i]) for i in range(1, len(module_path) + 1)
+ ]
+ return any(subpath in authorized_imports for subpath in module_subpaths)
if isinstance(expression, ast.Import):
for alias in expression.names:
@@ -821,20 +1053,47 @@ def check_module_authorized(module_name):
return None
-def evaluate_dictcomp(dictcomp, state, static_tools, custom_tools):
+def evaluate_dictcomp(
+ dictcomp: ast.DictComp,
+ state: Dict[str, Any],
+ static_tools: Dict[str, Callable],
+ custom_tools: Dict[str, Callable],
+ authorized_imports: List[str],
+) -> Dict[Any, Any]:
result = {}
for gen in dictcomp.generators:
- iter_value = evaluate_ast(gen.iter, state, static_tools, custom_tools)
+ iter_value = evaluate_ast(
+ gen.iter, state, static_tools, custom_tools, authorized_imports
+ )
for value in iter_value:
new_state = state.copy()
- set_value(gen.target, value, new_state, static_tools, custom_tools)
+ set_value(
+ gen.target,
+ value,
+ new_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
+ )
if all(
- evaluate_ast(if_clause, new_state, static_tools, custom_tools)
+ evaluate_ast(
+ if_clause, new_state, static_tools, custom_tools, authorized_imports
+ )
for if_clause in gen.ifs
):
- key = evaluate_ast(dictcomp.key, new_state, static_tools, custom_tools)
+ key = evaluate_ast(
+ dictcomp.key,
+ new_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
+ )
val = evaluate_ast(
- dictcomp.value, new_state, static_tools, custom_tools
+ dictcomp.value,
+ new_state,
+ static_tools,
+ custom_tools,
+ authorized_imports,
)
result[key] = val
return result
@@ -865,7 +1124,7 @@ def evaluate_ast(
Functions that may be called during the evaluation. These static_tools can be overwritten.
authorized_imports (`List[str]`):
The list of modules that can be imported by the code. By default, only a few safe modules are allowed.
- Add more at your own risk!
+ If it contains "*", it will authorize any import. Use this at your own risk!
"""
global OPERATIONS_COUNT
if OPERATIONS_COUNT >= MAX_OPERATIONS:
@@ -876,131 +1135,202 @@ def evaluate_ast(
if isinstance(expression, ast.Assign):
# Assignment -> we evaluate the assignment which should update the state
# We return the variable assigned as it may be used to determine the final result.
- return evaluate_assign(expression, state, static_tools, custom_tools)
+ return evaluate_assign(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.AugAssign):
- return evaluate_augassign(expression, state, static_tools, custom_tools)
+ return evaluate_augassign(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Call):
# Function call -> we return the value of the function call
- return evaluate_call(expression, state, static_tools, custom_tools)
+ return evaluate_call(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Constant):
# Constant -> just return the value
return expression.value
elif isinstance(expression, ast.Tuple):
return tuple(
- evaluate_ast(elt, state, static_tools, custom_tools)
+ evaluate_ast(elt, state, static_tools, custom_tools, authorized_imports)
for elt in expression.elts
)
elif isinstance(expression, (ast.ListComp, ast.GeneratorExp)):
- return evaluate_listcomp(expression, state, static_tools, custom_tools)
+ return evaluate_listcomp(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.UnaryOp):
- return evaluate_unaryop(expression, state, static_tools, custom_tools)
+ return evaluate_unaryop(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Starred):
- return evaluate_ast(expression.value, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.BoolOp):
# Boolean operation -> evaluate the operation
- return evaluate_boolop(expression, state, static_tools, custom_tools)
+ return evaluate_boolop(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Break):
raise BreakException()
elif isinstance(expression, ast.Continue):
raise ContinueException()
elif isinstance(expression, ast.BinOp):
# Binary operation -> execute operation
- return evaluate_binop(expression, state, static_tools, custom_tools)
+ return evaluate_binop(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Compare):
# Comparison -> evaluate the comparison
- return evaluate_condition(expression, state, static_tools, custom_tools)
+ return evaluate_condition(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Lambda):
- return evaluate_lambda(expression, state, static_tools, custom_tools)
+ return evaluate_lambda(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.FunctionDef):
- return evaluate_function_def(expression, state, static_tools, custom_tools)
+ return evaluate_function_def(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Dict):
# Dict -> evaluate all keys and values
keys = [
- evaluate_ast(k, state, static_tools, custom_tools) for k in expression.keys
+ evaluate_ast(k, state, static_tools, custom_tools, authorized_imports)
+ for k in expression.keys
]
values = [
- evaluate_ast(v, state, static_tools, custom_tools)
+ evaluate_ast(v, state, static_tools, custom_tools, authorized_imports)
for v in expression.values
]
return dict(zip(keys, values))
elif isinstance(expression, ast.Expr):
# Expression -> evaluate the content
- return evaluate_ast(expression.value, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.For):
# For loop -> execute the loop
- return evaluate_for(expression, state, static_tools, custom_tools)
+ return evaluate_for(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.FormattedValue):
# Formatted value (part of f-string) -> evaluate the content and return
- return evaluate_ast(expression.value, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.If):
# If -> execute the right branch
- return evaluate_if(expression, state, static_tools, custom_tools)
+ return evaluate_if(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif hasattr(ast, "Index") and isinstance(expression, ast.Index):
- return evaluate_ast(expression.value, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.JoinedStr):
return "".join(
[
- str(evaluate_ast(v, state, static_tools, custom_tools))
+ str(
+ evaluate_ast(
+ v, state, static_tools, custom_tools, authorized_imports
+ )
+ )
for v in expression.values
]
)
elif isinstance(expression, ast.List):
# List -> evaluate all elements
return [
- evaluate_ast(elt, state, static_tools, custom_tools)
+ evaluate_ast(elt, state, static_tools, custom_tools, authorized_imports)
for elt in expression.elts
]
elif isinstance(expression, ast.Name):
# Name -> pick up the value in the state
- return evaluate_name(expression, state, static_tools, custom_tools)
+ return evaluate_name(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Subscript):
# Subscript -> return the value of the indexing
- return evaluate_subscript(expression, state, static_tools, custom_tools)
+ return evaluate_subscript(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.IfExp):
- test_val = evaluate_ast(expression.test, state, static_tools, custom_tools)
+ test_val = evaluate_ast(
+ expression.test, state, static_tools, custom_tools, authorized_imports
+ )
if test_val:
- return evaluate_ast(expression.body, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.body, state, static_tools, custom_tools, authorized_imports
+ )
else:
- return evaluate_ast(expression.orelse, state, static_tools, custom_tools)
+ return evaluate_ast(
+ expression.orelse, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Attribute):
- value = evaluate_ast(expression.value, state, static_tools, custom_tools)
+ value = evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
return getattr(value, expression.attr)
elif isinstance(expression, ast.Slice):
return slice(
- evaluate_ast(expression.lower, state, static_tools, custom_tools)
+ evaluate_ast(
+ expression.lower, state, static_tools, custom_tools, authorized_imports
+ )
if expression.lower is not None
else None,
- evaluate_ast(expression.upper, state, static_tools, custom_tools)
+ evaluate_ast(
+ expression.upper, state, static_tools, custom_tools, authorized_imports
+ )
if expression.upper is not None
else None,
- evaluate_ast(expression.step, state, static_tools, custom_tools)
+ evaluate_ast(
+ expression.step, state, static_tools, custom_tools, authorized_imports
+ )
if expression.step is not None
else None,
)
elif isinstance(expression, ast.DictComp):
- return evaluate_dictcomp(expression, state, static_tools, custom_tools)
+ return evaluate_dictcomp(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.While):
- return evaluate_while(expression, state, static_tools, custom_tools)
+ return evaluate_while(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, (ast.Import, ast.ImportFrom)):
return import_modules(expression, state, authorized_imports)
elif isinstance(expression, ast.ClassDef):
- return evaluate_class_def(expression, state, static_tools, custom_tools)
+ return evaluate_class_def(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Try):
- return evaluate_try(expression, state, static_tools, custom_tools)
+ return evaluate_try(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Raise):
- return evaluate_raise(expression, state, static_tools, custom_tools)
+ return evaluate_raise(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Assert):
- return evaluate_assert(expression, state, static_tools, custom_tools)
+ return evaluate_assert(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.With):
- return evaluate_with(expression, state, static_tools, custom_tools)
+ return evaluate_with(
+ expression, state, static_tools, custom_tools, authorized_imports
+ )
elif isinstance(expression, ast.Set):
return {
- evaluate_ast(elt, state, static_tools, custom_tools)
+ evaluate_ast(elt, state, static_tools, custom_tools, authorized_imports)
for elt in expression.elts
}
elif isinstance(expression, ast.Return):
raise ReturnException(
- evaluate_ast(expression.value, state, static_tools, custom_tools)
+ evaluate_ast(
+ expression.value, state, static_tools, custom_tools, authorized_imports
+ )
if expression.value
else None
)
diff --git a/src/smolagents/models.py b/src/smolagents/models.py
index cc9aedc42..a8901e0ef 100644
--- a/src/smolagents/models.py
+++ b/src/smolagents/models.py
@@ -361,7 +361,7 @@ def __call__(
)
prompt_tensor = prompt_tensor.to(self.model.device)
count_prompt_tokens = prompt_tensor["input_ids"].shape[1]
-
+
out = self.model.generate(
**prompt_tensor,
max_new_tokens=max_tokens,
diff --git a/tests/test_agents.py b/tests/test_agents.py
index f51ce9fe9..0a90d2b84 100644
--- a/tests/test_agents.py
+++ b/tests/test_agents.py
@@ -313,9 +313,11 @@ def test_fake_code_agent(self):
assert isinstance(output, float)
assert output == 7.2904
assert agent.logs[1].task == "What is 2 multiplied by 3.6452?"
- assert agent.logs[3].tool_call == ToolCall(
- name="python_interpreter", arguments="final_answer(7.2904)", id="call_3"
- )
+ assert agent.logs[3].tool_calls == [
+ ToolCall(
+ name="python_interpreter", arguments="final_answer(7.2904)", id="call_3"
+ )
+ ]
def test_additional_args_added_to_task(self):
agent = CodeAgent(tools=[], model=fake_code_model)
From ad180410789af353b0a13e601b8598813fde2ffa Mon Sep 17 00:00:00 2001
From: tanhuajie <68807603+tanhuajie@users.noreply.github.com>
Date: Tue, 14 Jan 2025 00:24:18 +0800
Subject: [PATCH 2/9] Fix tool_calls parsing error in ToolCallingAgent (#160)
---
src/smolagents/agents.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/smolagents/agents.py b/src/smolagents/agents.py
index 832ac8efc..5741ce9d7 100644
--- a/src/smolagents/agents.py
+++ b/src/smolagents/agents.py
@@ -15,6 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
+import json
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
@@ -806,9 +807,17 @@ def step(self, log_entry: ActionStep) -> Union[None, Any]:
tools_to_call_from=list(self.tools.values()),
stop_sequences=["Observation:"],
)
- tool_calls = model_message.tool_calls[0]
- tool_arguments = tool_calls.function.arguments
- tool_name, tool_call_id = tool_calls.function.name, tool_calls.id
+
+ # Extract tool call from model output
+ if type(model_message.tool_calls) is list and len(model_message.tool_calls) > 0:
+ tool_calls = model_message.tool_calls[0]
+ tool_arguments = tool_calls.function.arguments
+ tool_name, tool_call_id = tool_calls.function.name, tool_calls.id
+ else:
+ start, end = model_message.content.find('{'), model_message.content.rfind('}') + 1
+ tool_calls = json.loads(model_message.content[start:end])
+ tool_arguments = tool_calls["tool_arguments"]
+ tool_name, tool_call_id = tool_calls["tool_name"], f"call_{len(self.logs)}"
except Exception as e:
raise AgentGenerationError(
From 1f96560c925a686eb901bff342526ca933c2c462 Mon Sep 17 00:00:00 2001
From: Albert Villanova del Moral
<8515462+albertvillanova@users.noreply.github.com>
Date: Mon, 13 Jan 2025 17:26:32 +0100
Subject: [PATCH 3/9] Fix minor issues in building_good_agents docs (#170)
* Fix doc inter-link to intro_agents in building_good_agents, make text italic, minor typos
---
docs/source/en/tutorials/building_good_agents.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/en/tutorials/building_good_agents.md b/docs/source/en/tutorials/building_good_agents.md
index 84f77eaf8..f2d37a20e 100644
--- a/docs/source/en/tutorials/building_good_agents.md
+++ b/docs/source/en/tutorials/building_good_agents.md
@@ -30,7 +30,7 @@ Giving an LLM some agency in your workflow introduces some risk of errors.
Well-programmed agentic systems have good error logging and retry mechanisms anyway, so the LLM engine has a chance to self-correct their mistake. But to reduce the risk of LLM error to the maximum, you should simplify your workflow!
-Let's revisit the example from [intro_agents]: a bot that answers user queries for a surf trip company.
+Let's revisit the example from the [intro to agents](../conceptual_guides/intro_agents): a bot that answers user queries for a surf trip company.
Instead of letting the agent do 2 different calls for "travel distance API" and "weather API" each time they are asked about a new surf spot, you could just make one unified tool "return_spot_information", a function that calls both APIs at once and returns their concatenated outputs to the user.
This will reduce costs, latency, and error risk!
@@ -43,7 +43,7 @@ This leads to a few takeaways:
### Improve the information flow to the LLM engine
-Remember that your LLM engine is like a ~intelligent~ robot, tapped into a room with the only communication with the outside world being notes passed under a door.
+Remember that your LLM engine is like an *intelligent* robot, tapped into a room with the only communication with the outside world being notes passed under a door.
It won't know of anything that happened if you don't explicitly put that into its prompt.
@@ -88,7 +88,7 @@ def get_weather_api(location: str, date_time: str) -> str:
Why is it bad?
- there's no precision of the format that should be used for `date_time`
- there's no detail on how location should be specified.
-- there's no logging mechanism tying to explicit failure cases like location not being in a proper format, or date_time not being properly formatted.
+- there's no logging mechanism trying to make explicit failure cases like location not being in a proper format, or date_time not being properly formatted.
- the output format is hard to understand
If the tool call fails, the error trace logged in memory can help the LLM reverse engineer the tool to fix the errors. But why leave it with so much heavy lifting to do?
From 1d846072eb5a33e429dc0c89dc68976b6114f5e2 Mon Sep 17 00:00:00 2001
From: Aymeric
Date: Mon, 13 Jan 2025 19:46:36 +0100
Subject: [PATCH 4/9] Improve GradioUI file upload system
---
examples/gradio_upload.py | 2 +-
src/smolagents/agents.py | 27 ++++++++++++------
src/smolagents/gradio_ui.py | 49 ++++++++++++++++++++++----------
src/smolagents/models.py | 28 ++++++------------
tests/test_agents.py | 3 +-
tests/test_python_interpreter.py | 1 +
6 files changed, 66 insertions(+), 44 deletions(-)
diff --git a/examples/gradio_upload.py b/examples/gradio_upload.py
index 1e5b4641d..4b8425d83 100644
--- a/examples/gradio_upload.py
+++ b/examples/gradio_upload.py
@@ -5,7 +5,7 @@
)
agent = CodeAgent(
- tools=[], model=HfApiModel(), max_steps=4, verbose=True
+ tools=[], model=HfApiModel(), max_steps=4, verbosity_level=0
)
GradioUI(agent, file_upload_folder='./data').launch()
diff --git a/src/smolagents/agents.py b/src/smolagents/agents.py
index 5741ce9d7..1c81727b8 100644
--- a/src/smolagents/agents.py
+++ b/src/smolagents/agents.py
@@ -396,7 +396,7 @@ def provide_final_answer(self, task) -> str:
}
]
try:
- return self.model(self.input_messages)
+ return self.model(self.input_messages).content
except Exception as e:
return f"Error in generating final LLM output:\n{e}"
@@ -666,7 +666,9 @@ def planning_step(self, task, is_first_step: bool, step: int):
Now begin!""",
}
- answer_facts = self.model([message_prompt_facts, message_prompt_task])
+ answer_facts = self.model(
+ [message_prompt_facts, message_prompt_task]
+ ).content
message_system_prompt_plan = {
"role": MessageRole.SYSTEM,
@@ -688,7 +690,7 @@ def planning_step(self, task, is_first_step: bool, step: int):
answer_plan = self.model(
[message_system_prompt_plan, message_user_prompt_plan],
stop_sequences=[""],
- )
+ ).content
final_plan_redaction = f"""Here is the plan of action that I will follow to solve the task:
```
@@ -722,7 +724,7 @@ def planning_step(self, task, is_first_step: bool, step: int):
}
facts_update = self.model(
[facts_update_system_prompt] + agent_memory + [facts_update_message]
- )
+ ).content
# Redact updated plan
plan_update_message = {
@@ -807,17 +809,26 @@ def step(self, log_entry: ActionStep) -> Union[None, Any]:
tools_to_call_from=list(self.tools.values()),
stop_sequences=["Observation:"],
)
-
+
# Extract tool call from model output
- if type(model_message.tool_calls) is list and len(model_message.tool_calls) > 0:
+ if (
+ type(model_message.tool_calls) is list
+ and len(model_message.tool_calls) > 0
+ ):
tool_calls = model_message.tool_calls[0]
tool_arguments = tool_calls.function.arguments
tool_name, tool_call_id = tool_calls.function.name, tool_calls.id
else:
- start, end = model_message.content.find('{'), model_message.content.rfind('}') + 1
+ start, end = (
+ model_message.content.find("{"),
+ model_message.content.rfind("}") + 1,
+ )
tool_calls = json.loads(model_message.content[start:end])
tool_arguments = tool_calls["tool_arguments"]
- tool_name, tool_call_id = tool_calls["tool_name"], f"call_{len(self.logs)}"
+ tool_name, tool_call_id = (
+ tool_calls["tool_name"],
+ f"call_{len(self.logs)}",
+ )
except Exception as e:
raise AgentGenerationError(
diff --git a/src/smolagents/gradio_ui.py b/src/smolagents/gradio_ui.py
index 45ae8a250..42a4183dc 100644
--- a/src/smolagents/gradio_ui.py
+++ b/src/smolagents/gradio_ui.py
@@ -27,14 +27,15 @@ def pull_messages_from_step(step_log: AgentStep, test_mode: bool = True):
"""Extract ChatMessage objects from agent steps"""
if isinstance(step_log, ActionStep):
yield gr.ChatMessage(role="assistant", content=step_log.llm_output or "")
- if step_log.tool_call is not None:
- used_code = step_log.tool_call.name == "code interpreter"
- content = step_log.tool_call.arguments
+ if step_log.tool_calls is not None:
+ first_tool_call = step_log.tool_calls[0]
+ used_code = first_tool_call.name == "code interpreter"
+ content = first_tool_call.arguments
if used_code:
content = f"```py\n{content}\n```"
yield gr.ChatMessage(
role="assistant",
- metadata={"title": f"🛠️ Used tool {step_log.tool_call.name}"},
+ metadata={"title": f"🛠️ Used tool {first_tool_call.name}"},
content=str(content),
)
if step_log.observations is not None:
@@ -103,6 +104,7 @@ def interact_with_agent(self, prompt, messages):
def upload_file(
self,
file,
+ file_uploads_log,
allowed_file_types=[
"application/pdf",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -110,14 +112,12 @@ def upload_file(
],
):
"""
- Handle file uploads, default allowed types are pdf, docx, and .txt
+ Handle file uploads, default allowed types are .pdf, .docx, and .txt
"""
- # Check if file is uploaded
if file is None:
return "No file uploaded"
- # Check if file is in allowed filetypes
try:
mime_type, _ = mimetypes.guess_type(file.name)
except Exception as e:
@@ -148,11 +148,23 @@ def upload_file(
)
shutil.copy(file.name, file_path)
- return f"File uploaded successfully to {self.file_upload_folder}"
+ return gr.Textbox(
+ f"File uploaded: {file_path}", visible=True
+ ), file_uploads_log + [file_path]
+
+ def log_user_message(self, text_input, file_uploads_log):
+ return (
+ text_input
+ + f"\nYou have been provided with these files, which might be helpful or not: {file_uploads_log}"
+ if len(file_uploads_log) > 0
+ else "",
+ "",
+ )
def launch(self):
with gr.Blocks() as demo:
- stored_message = gr.State([])
+ stored_messages = gr.State([])
+ file_uploads_log = gr.State([])
chatbot = gr.Chatbot(
label="Agent",
type="messages",
@@ -163,14 +175,21 @@ def launch(self):
)
# If an upload folder is provided, enable the upload feature
if self.file_upload_folder is not None:
- upload_file = gr.File(label="Upload a file")
- upload_status = gr.Textbox(label="Upload Status", interactive=False)
-
- upload_file.change(self.upload_file, [upload_file], [upload_status])
+ upload_file = gr.File(label="Upload a file", height=1)
+ upload_status = gr.Textbox(
+ label="Upload Status", interactive=False, visible=False
+ )
+ upload_file.change(
+ self.upload_file,
+ [upload_file, file_uploads_log],
+ [upload_status, file_uploads_log],
+ )
text_input = gr.Textbox(lines=1, label="Chat Message")
text_input.submit(
- lambda s: (s, ""), [text_input], [stored_message, text_input]
- ).then(self.interact_with_agent, [stored_message, chatbot], [chatbot])
+ self.log_user_message,
+ [text_input, file_uploads_log],
+ [stored_messages, text_input],
+ ).then(self.interact_with_agent, [stored_messages, chatbot], [chatbot])
demo.launch()
diff --git a/src/smolagents/models.py b/src/smolagents/models.py
index a8901e0ef..a57550ad6 100644
--- a/src/smolagents/models.py
+++ b/src/smolagents/models.py
@@ -36,6 +36,8 @@
StoppingCriteriaList,
is_torch_available,
)
+from transformers.utils.import_utils import _is_package_available
+
import openai
from .tools import Tool
@@ -52,13 +54,9 @@
"value": "Thought: .+?\\nCode:\\n```(?:py|python)?\\n(?:.|\\s)+?\\n```",
}
-try:
+if _is_package_available("litellm"):
import litellm
- is_litellm_available = True
-except ImportError:
- is_litellm_available = False
-
class MessageRole(str, Enum):
USER = "user"
@@ -159,7 +157,7 @@ def __call__(
stop_sequences: Optional[List[str]] = None,
grammar: Optional[str] = None,
max_tokens: int = 1500,
- ) -> str:
+ ) -> ChatCompletionOutputMessage:
"""Process the input messages and return the model's response.
Parameters:
@@ -174,15 +172,7 @@ def __call__(
Returns:
`str`: The text content of the model's response.
"""
- if not isinstance(messages, List):
- raise ValueError(
- "Messages should be a list of dictionaries with 'role' and 'content' keys."
- )
- if stop_sequences is None:
- stop_sequences = []
- response = self.generate(messages, stop_sequences, grammar, max_tokens)
-
- return remove_stop_sequences(response, stop_sequences)
+ pass # To be implemented in child classes!
class HfApiModel(Model):
@@ -238,7 +228,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> str:
+ ) -> ChatCompletionOutputMessage:
"""
Gets an LLM output message for the given list of input messages.
If argument `tools_to_call_from` is passed, the model's tool calling options will be used to return a tool call.
@@ -407,7 +397,7 @@ def __init__(
api_key=None,
**kwargs,
):
- if not is_litellm_available:
+ if not _is_package_available("litellm"):
raise ImportError(
"litellm not found. Install it with `pip install litellm`"
)
@@ -426,7 +416,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> str:
+ ) -> ChatCompletionOutputMessage:
messages = get_clean_message_list(
messages, role_conversions=tool_role_conversions
)
@@ -497,7 +487,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> str:
+ ) -> ChatCompletionOutputMessage:
messages = get_clean_message_list(
messages, role_conversions=tool_role_conversions
)
diff --git a/tests/test_agents.py b/tests/test_agents.py
index 0a90d2b84..38538cebc 100644
--- a/tests/test_agents.py
+++ b/tests/test_agents.py
@@ -367,9 +367,10 @@ def test_fails_max_steps(self):
model=fake_code_model_no_return, # use this callable because it never ends
max_steps=5,
)
- agent.run("What is 2 multiplied by 3.6452?")
+ answer = agent.run("What is 2 multiplied by 3.6452?")
assert len(agent.logs) == 8
assert type(agent.logs[-1].error) is AgentMaxStepsError
+ assert isinstance(answer, str)
def test_tool_descriptions_get_baked_in_system_prompt(self):
tool = PythonInterpreterTool()
diff --git a/tests/test_python_interpreter.py b/tests/test_python_interpreter.py
index 59440665b..8c7aacc9c 100644
--- a/tests/test_python_interpreter.py
+++ b/tests/test_python_interpreter.py
@@ -486,6 +486,7 @@ def test_additional_imports(self):
code = "import numpy.random as rd"
evaluate_python_code(code, authorized_imports=["numpy.random"], state={})
evaluate_python_code(code, authorized_imports=["numpy"], state={})
+ evaluate_python_code(code, authorized_imports=["*"], state={})
with pytest.raises(InterpreterError):
evaluate_python_code(code, authorized_imports=["random"], state={})
From c04e8de8250467dec047690b1db9b7dd01b2650b Mon Sep 17 00:00:00 2001
From: Ilya Gusev
Date: Tue, 14 Jan 2025 09:58:45 +0100
Subject: [PATCH 5/9] Bugfix: Fix plan_update message display (#179)
---
src/smolagents/agents.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/smolagents/agents.py b/src/smolagents/agents.py
index 1c81727b8..b3d0c5a78 100644
--- a/src/smolagents/agents.py
+++ b/src/smolagents/agents.py
@@ -748,7 +748,7 @@ def planning_step(self, task, is_first_step: bool, step: int):
plan_update = self.model(
[plan_update_message] + agent_memory + [plan_update_message_user],
stop_sequences=[""],
- )
+ ).content
# Log final facts and plan
final_plan_redaction = PLAN_UPDATE_FINAL_PLAN_REDACTION.format(
From 12a2e6f4b4eadf94a57034b073672e8b115ac89c Mon Sep 17 00:00:00 2001
From: Deng Tongwei <74892366+6643789wsx@users.noreply.github.com>
Date: Tue, 14 Jan 2025 17:00:08 +0800
Subject: [PATCH 6/9] feat: Add multi-GPU support for TransformersModel (#139)
Add multi-GPU support for TransformersModel
---
src/smolagents/models.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/smolagents/models.py b/src/smolagents/models.py
index a57550ad6..70ef5d196 100644
--- a/src/smolagents/models.py
+++ b/src/smolagents/models.py
@@ -287,16 +287,14 @@ def __init__(self, model_id: Optional[str] = None, device: Optional[str] = None)
logger.info(f"Using device: {self.device}")
try:
self.tokenizer = AutoTokenizer.from_pretrained(model_id)
- self.model = AutoModelForCausalLM.from_pretrained(model_id).to(self.device)
+ self.model = AutoModelForCausalLM.from_pretrained(model_id, device_map=self.device)
except Exception as e:
logger.warning(
f"Failed to load tokenizer and model for {model_id=}: {e}. Loading default tokenizer and model instead from {default_model_id=}."
)
self.model_id = default_model_id
self.tokenizer = AutoTokenizer.from_pretrained(default_model_id)
- self.model = AutoModelForCausalLM.from_pretrained(default_model_id).to(
- self.device
- )
+ self.model = AutoModelForCausalLM.from_pretrained(model_id, device_map=self.device)
def make_stopping_criteria(self, stop_sequences: List[str]) -> StoppingCriteriaList:
class StopOnStrings(StoppingCriteria):
From 5f323735511f54168b688cdb0dee10ab5bdcd909 Mon Sep 17 00:00:00 2001
From: Aymeric Roucher <69208727+aymeric-roucher@users.noreply.github.com>
Date: Tue, 14 Jan 2025 14:57:11 +0100
Subject: [PATCH 7/9] Make default tools more robust (#186)
---
.github/workflows/tests.yml | 3 +
examples/benchmark.ipynb | 301 +++++++++----------------------
src/smolagents/agents.py | 29 +--
src/smolagents/default_tools.py | 24 ++-
src/smolagents/models.py | 60 ++++--
src/smolagents/tools.py | 10 +
tests/test_agents.py | 78 ++++----
tests/test_default_tools.py | 83 +++++++++
tests/test_monitoring.py | 18 +-
tests/test_python_interpreter.py | 46 +----
10 files changed, 296 insertions(+), 356 deletions(-)
create mode 100644 tests/test_default_tools.py
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a595bede2..c720ec0f5 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -36,6 +36,9 @@ jobs:
- name: Agent tests
run: |
uv run pytest -sv ./tests/test_agents.py
+ - name: Default tools tests
+ run: |
+ uv run pytest -sv ./tests/test_default_tools.py
- name: Final answer tests
run: |
uv run pytest -sv ./tests/test_final_answer.py
diff --git a/examples/benchmark.ipynb b/examples/benchmark.ipynb
index 1009f2807..8b49b0aa2 100644
--- a/examples/benchmark.ipynb
+++ b/examples/benchmark.ipynb
@@ -21,7 +21,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 4,
"metadata": {},
"outputs": [
{
@@ -29,8 +29,7 @@
"output_type": "stream",
"text": [
"/Users/aymeric/venv/test/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
- " from .autonotebook import tqdm as notebook_tqdm\n",
- "Generating train split: 100%|██████████| 132/132 [00:00<00:00, 17393.36 examples/s]\n"
+ " from .autonotebook import tqdm as notebook_tqdm\n"
]
},
{
@@ -173,7 +172,7 @@
"[132 rows x 4 columns]"
]
},
- "execution_count": 5,
+ "execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
@@ -196,19 +195,9 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/Users/aymeric/venv/test/lib/python3.12/site-packages/pydantic/_internal/_config.py:345: UserWarning: Valid config keys have changed in V2:\n",
- "* 'fields' has been removed\n",
- " warnings.warn(message, UserWarning)\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"import time\n",
"import json\n",
@@ -408,100 +397,9 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'meta-llama/Llama-3.3-70B-Instruct'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 27061.35it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 34618.15it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'Qwen/Qwen2.5-72B-Instruct'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 33008.29it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 36292.90it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'Qwen/Qwen2.5-Coder-32B-Instruct'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 29165.47it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 30378.50it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'meta-llama/Llama-3.2-3B-Instruct'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 33453.06it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 34763.79it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'meta-llama/Llama-3.1-8B-Instruct'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 35246.25it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 28551.81it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'mistralai/Mistral-Nemo-Instruct-2407'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 32441.59it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 35542.67it/s]\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"open_model_ids = [\n",
" \"meta-llama/Llama-3.3-70B-Instruct\",\n",
@@ -554,42 +452,9 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'gpt-4o'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 36136.55it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 33451.04it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 39146.44it/s]\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Evaluating 'anthropic/claude-3-5-sonnet-latest'...\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "100%|██████████| 132/132 [00:00<00:00, 31512.79it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 33576.82it/s]\n",
- "100%|██████████| 132/132 [00:00<00:00, 36075.33it/s]\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"from smolagents import LiteLLMModel\n",
"\n",
@@ -614,7 +479,7 @@
" agent = CodeAgent(\n",
" tools=[GoogleSearchTool(), VisitWebpageTool()],\n",
" model=LiteLLMModel(model_id),\n",
- " additional_authorized_imports=[\"numpy\"],\n",
+ " additional_authorized_imports=[\"numpy\", \"sympy\"],\n",
" max_steps=10,\n",
" )\n",
" file_name = f\"output/{model_id.replace('/', '_')}-{action_type}-26-dec-2024.jsonl\"\n",
@@ -631,34 +496,39 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# import glob\n",
"# import json\n",
+ "\n",
"# jsonl_files = glob.glob(f\"output/*.jsonl\")\n",
"\n",
"# for file_path in jsonl_files:\n",
- "# print(file_path)\n",
- "# # Read all lines and filter out SimpleQA sources\n",
- "# filtered_lines = []\n",
- "# removed = 0\n",
- "# with open(file_path, 'r', encoding='utf-8') as f:\n",
- "# for line in f:\n",
- "# try:\n",
- "# data = json.loads(line.strip())\n",
- "# if not any([question in data[\"question\"] for question in eval_ds[\"question\"]]):\n",
- "# removed +=1\n",
- "# else:\n",
- "# filtered_lines.append(line)\n",
- "# except json.JSONDecodeError:\n",
- "# print(\"Invalid line:\", line)\n",
- "# continue # Skip invalid JSON lines\n",
- "# print(f\"Removed {removed} lines.\")\n",
- "# # Write filtered content back to the same file\n",
- "# with open(file_path, 'w', encoding='utf-8') as f:\n",
- "# f.writelines(filtered_lines)"
+ "# if \"-Nemo-\" in file_path and \"-vanilla-\" in file_path:\n",
+ "# print(file_path)\n",
+ "# # Read all lines and filter out SimpleQA sources\n",
+ "# filtered_lines = []\n",
+ "# removed = 0\n",
+ "# with open(file_path, \"r\", encoding=\"utf-8\") as f:\n",
+ "# for line in f:\n",
+ "# try:\n",
+ "# data = json.loads(line.strip())\n",
+ "# data[\"answer\"] = data[\"answer\"][\"content\"]\n",
+ "# # if not any([question in data[\"question\"] for question in eval_ds[\"question\"]]):\n",
+ "# # removed +=1\n",
+ "# # else:\n",
+ "# filtered_lines.append(json.dumps(data) + \"\\n\")\n",
+ "# except json.JSONDecodeError:\n",
+ "# print(\"Invalid line:\", line)\n",
+ "# continue # Skip invalid JSON lines\n",
+ "# print(f\"Removed {removed} lines.\")\n",
+ "# # Write filtered content back to the same file\n",
+ "# with open(\n",
+ "# str(file_path).replace(\"-vanilla-\", \"-vanilla2-\"), \"w\", encoding=\"utf-8\"\n",
+ "# ) as f:\n",
+ "# f.writelines(filtered_lines)"
]
},
{
@@ -670,14 +540,14 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
- "/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/ipykernel_6037/1901135017.py:164: UserWarning: Answer lists have different lengths, returning False.\n",
+ "/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/ipykernel_27085/1901135017.py:164: UserWarning: Answer lists have different lengths, returning False.\n",
" warnings.warn(\n"
]
}
@@ -731,7 +601,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
@@ -752,7 +622,7 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 11,
"metadata": {},
"outputs": [
{
@@ -794,28 +664,28 @@
" 1 | \n",
" Qwen/Qwen2.5-72B-Instruct | \n",
" MATH | \n",
- " 74.0 | \n",
+ " 76.0 | \n",
" 30.0 | \n",
" \n",
" \n",
" | 2 | \n",
" Qwen/Qwen2.5-72B-Instruct | \n",
" SimpleQA | \n",
- " 70.0 | \n",
+ " 88.0 | \n",
" 10.0 | \n",
"
\n",
" \n",
" | 3 | \n",
" Qwen/Qwen2.5-Coder-32B-Instruct | \n",
" GAIA | \n",
- " 18.8 | \n",
+ " 25.0 | \n",
" 3.1 | \n",
"
\n",
" \n",
" | 4 | \n",
" Qwen/Qwen2.5-Coder-32B-Instruct | \n",
" MATH | \n",
- " 76.0 | \n",
+ " 86.0 | \n",
" 60.0 | \n",
"
\n",
" \n",
@@ -829,63 +699,63 @@
" | 6 | \n",
" anthropic/claude-3-5-sonnet-latest | \n",
" GAIA | \n",
- " 40.6 | \n",
+ " NaN | \n",
" 3.1 | \n",
"
\n",
" \n",
" | 7 | \n",
" anthropic/claude-3-5-sonnet-latest | \n",
" MATH | \n",
- " 67.0 | \n",
+ " NaN | \n",
" 50.0 | \n",
"
\n",
" \n",
" | 8 | \n",
" anthropic/claude-3-5-sonnet-latest | \n",
" SimpleQA | \n",
- " 90.0 | \n",
+ " NaN | \n",
" 34.0 | \n",
"
\n",
" \n",
" | 9 | \n",
" gpt-4o | \n",
" GAIA | \n",
- " 28.1 | \n",
+ " 25.6 | \n",
" 3.1 | \n",
"
\n",
" \n",
" | 10 | \n",
" gpt-4o | \n",
" MATH | \n",
- " 70.0 | \n",
+ " 58.0 | \n",
" 40.0 | \n",
"
\n",
" \n",
" | 11 | \n",
" gpt-4o | \n",
" SimpleQA | \n",
- " 88.0 | \n",
+ " 86.0 | \n",
" 6.0 | \n",
"
\n",
" \n",
" | 12 | \n",
" meta-llama/Llama-3.1-8B-Instruct | \n",
" GAIA | \n",
- " 0.0 | \n",
+ " 3.1 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 13 | \n",
" meta-llama/Llama-3.1-8B-Instruct | \n",
" MATH | \n",
- " 42.0 | \n",
+ " 14.0 | \n",
" 18.0 | \n",
"
\n",
" \n",
" | 14 | \n",
" meta-llama/Llama-3.1-8B-Instruct | \n",
" SimpleQA | \n",
- " 54.0 | \n",
+ " 2.0 | \n",
" 6.0 | \n",
"
\n",
" \n",
@@ -899,49 +769,49 @@
" | 16 | \n",
" meta-llama/Llama-3.2-3B-Instruct | \n",
" MATH | \n",
- " 32.0 | \n",
+ " 40.0 | \n",
" 12.0 | \n",
"
\n",
" \n",
" | 17 | \n",
" meta-llama/Llama-3.2-3B-Instruct | \n",
" SimpleQA | \n",
- " 4.0 | \n",
+ " 20.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 18 | \n",
" meta-llama/Llama-3.3-70B-Instruct | \n",
" GAIA | \n",
- " 34.4 | \n",
+ " 31.2 | \n",
" 3.1 | \n",
"
\n",
" \n",
" | 19 | \n",
" meta-llama/Llama-3.3-70B-Instruct | \n",
" MATH | \n",
- " 82.0 | \n",
+ " 72.0 | \n",
" 40.0 | \n",
"
\n",
" \n",
" | 20 | \n",
" meta-llama/Llama-3.3-70B-Instruct | \n",
" SimpleQA | \n",
- " 84.0 | \n",
+ " 78.0 | \n",
" 12.0 | \n",
"
\n",
" \n",
" | 21 | \n",
" mistralai/Mistral-Nemo-Instruct-2407 | \n",
" GAIA | \n",
- " 3.1 | \n",
" 0.0 | \n",
+ " 3.1 | \n",
"
\n",
" \n",
" | 22 | \n",
" mistralai/Mistral-Nemo-Instruct-2407 | \n",
" MATH | \n",
- " 20.0 | \n",
+ " 30.0 | \n",
" 22.0 | \n",
"
\n",
" \n",
@@ -949,7 +819,7 @@
" | mistralai/Mistral-Nemo-Instruct-2407 | \n",
" SimpleQA | \n",
" 30.0 | \n",
- " 0.0 | \n",
+ " 6.0 | \n",
"
\n",
" \n",
"\n",
@@ -958,29 +828,29 @@
"text/plain": [
"action_type model_id source code vanilla\n",
"0 Qwen/Qwen2.5-72B-Instruct GAIA 28.1 6.2\n",
- "1 Qwen/Qwen2.5-72B-Instruct MATH 74.0 30.0\n",
- "2 Qwen/Qwen2.5-72B-Instruct SimpleQA 70.0 10.0\n",
- "3 Qwen/Qwen2.5-Coder-32B-Instruct GAIA 18.8 3.1\n",
- "4 Qwen/Qwen2.5-Coder-32B-Instruct MATH 76.0 60.0\n",
+ "1 Qwen/Qwen2.5-72B-Instruct MATH 76.0 30.0\n",
+ "2 Qwen/Qwen2.5-72B-Instruct SimpleQA 88.0 10.0\n",
+ "3 Qwen/Qwen2.5-Coder-32B-Instruct GAIA 25.0 3.1\n",
+ "4 Qwen/Qwen2.5-Coder-32B-Instruct MATH 86.0 60.0\n",
"5 Qwen/Qwen2.5-Coder-32B-Instruct SimpleQA 86.0 8.0\n",
- "6 anthropic/claude-3-5-sonnet-latest GAIA 40.6 3.1\n",
- "7 anthropic/claude-3-5-sonnet-latest MATH 67.0 50.0\n",
- "8 anthropic/claude-3-5-sonnet-latest SimpleQA 90.0 34.0\n",
- "9 gpt-4o GAIA 28.1 3.1\n",
- "10 gpt-4o MATH 70.0 40.0\n",
- "11 gpt-4o SimpleQA 88.0 6.0\n",
- "12 meta-llama/Llama-3.1-8B-Instruct GAIA 0.0 0.0\n",
- "13 meta-llama/Llama-3.1-8B-Instruct MATH 42.0 18.0\n",
- "14 meta-llama/Llama-3.1-8B-Instruct SimpleQA 54.0 6.0\n",
+ "6 anthropic/claude-3-5-sonnet-latest GAIA NaN 3.1\n",
+ "7 anthropic/claude-3-5-sonnet-latest MATH NaN 50.0\n",
+ "8 anthropic/claude-3-5-sonnet-latest SimpleQA NaN 34.0\n",
+ "9 gpt-4o GAIA 25.6 3.1\n",
+ "10 gpt-4o MATH 58.0 40.0\n",
+ "11 gpt-4o SimpleQA 86.0 6.0\n",
+ "12 meta-llama/Llama-3.1-8B-Instruct GAIA 3.1 0.0\n",
+ "13 meta-llama/Llama-3.1-8B-Instruct MATH 14.0 18.0\n",
+ "14 meta-llama/Llama-3.1-8B-Instruct SimpleQA 2.0 6.0\n",
"15 meta-llama/Llama-3.2-3B-Instruct GAIA 3.1 0.0\n",
- "16 meta-llama/Llama-3.2-3B-Instruct MATH 32.0 12.0\n",
- "17 meta-llama/Llama-3.2-3B-Instruct SimpleQA 4.0 0.0\n",
- "18 meta-llama/Llama-3.3-70B-Instruct GAIA 34.4 3.1\n",
- "19 meta-llama/Llama-3.3-70B-Instruct MATH 82.0 40.0\n",
- "20 meta-llama/Llama-3.3-70B-Instruct SimpleQA 84.0 12.0\n",
- "21 mistralai/Mistral-Nemo-Instruct-2407 GAIA 3.1 0.0\n",
- "22 mistralai/Mistral-Nemo-Instruct-2407 MATH 20.0 22.0\n",
- "23 mistralai/Mistral-Nemo-Instruct-2407 SimpleQA 30.0 0.0"
+ "16 meta-llama/Llama-3.2-3B-Instruct MATH 40.0 12.0\n",
+ "17 meta-llama/Llama-3.2-3B-Instruct SimpleQA 20.0 0.0\n",
+ "18 meta-llama/Llama-3.3-70B-Instruct GAIA 31.2 3.1\n",
+ "19 meta-llama/Llama-3.3-70B-Instruct MATH 72.0 40.0\n",
+ "20 meta-llama/Llama-3.3-70B-Instruct SimpleQA 78.0 12.0\n",
+ "21 mistralai/Mistral-Nemo-Instruct-2407 GAIA 0.0 3.1\n",
+ "22 mistralai/Mistral-Nemo-Instruct-2407 MATH 30.0 22.0\n",
+ "23 mistralai/Mistral-Nemo-Instruct-2407 SimpleQA 30.0 6.0"
]
},
"metadata": {},
@@ -1005,6 +875,15 @@
},
"metadata": {},
"output_type": "display_data"
+ },
+ {
+ "ename": "",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31mnotebook controller is DISPOSED. \n",
+ "\u001b[1;31mView Jupyter log for further details."
+ ]
}
],
"source": [
diff --git a/src/smolagents/agents.py b/src/smolagents/agents.py
index b3d0c5a78..cfa8a6ff4 100644
--- a/src/smolagents/agents.py
+++ b/src/smolagents/agents.py
@@ -15,7 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
-import json
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
@@ -809,26 +808,9 @@ def step(self, log_entry: ActionStep) -> Union[None, Any]:
tools_to_call_from=list(self.tools.values()),
stop_sequences=["Observation:"],
)
-
- # Extract tool call from model output
- if (
- type(model_message.tool_calls) is list
- and len(model_message.tool_calls) > 0
- ):
- tool_calls = model_message.tool_calls[0]
- tool_arguments = tool_calls.function.arguments
- tool_name, tool_call_id = tool_calls.function.name, tool_calls.id
- else:
- start, end = (
- model_message.content.find("{"),
- model_message.content.rfind("}") + 1,
- )
- tool_calls = json.loads(model_message.content[start:end])
- tool_arguments = tool_calls["tool_arguments"]
- tool_name, tool_call_id = (
- tool_calls["tool_name"],
- f"call_{len(self.logs)}",
- )
+ tool_call = model_message.tool_calls[0]
+ tool_name, tool_call_id = tool_call.function.name, tool_call.id
+ tool_arguments = tool_call.function.arguments
except Exception as e:
raise AgentGenerationError(
@@ -887,7 +869,10 @@ def step(self, log_entry: ActionStep) -> Union[None, Any]:
updated_information = f"Stored '{observation_name}' in memory."
else:
updated_information = str(observation).strip()
- self.logger.log(f"Observations: {updated_information}", level=LogLevel.INFO)
+ self.logger.log(
+ f"Observations: {updated_information.replace('[', '|')}", # escape potential rich-tag-like components
+ level=LogLevel.INFO,
+ )
log_entry.observations = updated_information
return None
diff --git a/src/smolagents/default_tools.py b/src/smolagents/default_tools.py
index 75fe8d017..59f6820f2 100644
--- a/src/smolagents/default_tools.py
+++ b/src/smolagents/default_tools.py
@@ -31,6 +31,7 @@
)
from .tools import TOOL_CONFIG_FILE, PipelineTool, Tool
from .types import AgentAudio
+from .utils import truncate_content
if is_torch_available():
from transformers.models.whisper import (
@@ -112,18 +113,15 @@ def __init__(self, *args, authorized_imports=None, **kwargs):
def forward(self, code: str) -> str:
state = {}
- try:
- output = str(
- self.python_evaluator(
- code,
- state=state,
- static_tools=self.base_python_tools,
- authorized_imports=self.authorized_imports,
- )[0] # The second element is boolean is_final_answer
- )
- return f"Stdout:\n{state['print_outputs']}\nOutput: {output}"
- except Exception as e:
- return f"Error: {str(e)}"
+ output = str(
+ self.python_evaluator(
+ code,
+ state=state,
+ static_tools=self.base_python_tools,
+ authorized_imports=self.authorized_imports,
+ )[0] # The second element is boolean is_final_answer
+ )
+ return f"Stdout:\n{state['print_outputs']}\nOutput: {output}"
class FinalAnswerTool(Tool):
@@ -295,7 +293,7 @@ def forward(self, url: str) -> str:
# Remove multiple line breaks
markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)
- return markdown_content
+ return truncate_content(markdown_content)
except RequestException as e:
return f"Error fetching the webpage: {str(e)}"
diff --git a/src/smolagents/models.py b/src/smolagents/models.py
index 70ef5d196..f25ced9c6 100644
--- a/src/smolagents/models.py
+++ b/src/smolagents/models.py
@@ -14,20 +14,16 @@
# 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.
+from dataclasses import dataclass
import json
import logging
import os
import random
from copy import deepcopy
from enum import Enum
-from typing import Dict, List, Optional
+from typing import Dict, List, Optional, Union, Any
-from huggingface_hub import (
- InferenceClient,
- ChatCompletionOutputMessage,
- ChatCompletionOutputToolCall,
- ChatCompletionOutputFunctionDefinition,
-)
+from huggingface_hub import InferenceClient
from transformers import (
AutoModelForCausalLM,
@@ -58,6 +54,27 @@
import litellm
+@dataclass
+class ChatMessageToolCallDefinition:
+ arguments: Any
+ name: str
+ description: Optional[str] = None
+
+
+@dataclass
+class ChatMessageToolCall:
+ function: ChatMessageToolCallDefinition
+ id: str
+ type: str
+
+
+@dataclass
+class ChatMessage:
+ role: str
+ content: Optional[str] = None
+ tool_calls: Optional[List[ChatMessageToolCall]] = None
+
+
class MessageRole(str, Enum):
USER = "user"
ASSISTANT = "assistant"
@@ -140,6 +157,17 @@ def get_clean_message_list(
return final_message_list
+def parse_dictionary(possible_dictionary: str) -> Union[Dict, str]:
+ try:
+ start, end = (
+ possible_dictionary.find("{"),
+ possible_dictionary.rfind("}") + 1,
+ )
+ return json.loads(possible_dictionary[start:end])
+ except Exception:
+ return possible_dictionary
+
+
class Model:
def __init__(self):
self.last_input_token_count = None
@@ -157,7 +185,7 @@ def __call__(
stop_sequences: Optional[List[str]] = None,
grammar: Optional[str] = None,
max_tokens: int = 1500,
- ) -> ChatCompletionOutputMessage:
+ ) -> ChatMessage:
"""Process the input messages and return the model's response.
Parameters:
@@ -228,7 +256,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> ChatCompletionOutputMessage:
+ ) -> ChatMessage:
"""
Gets an LLM output message for the given list of input messages.
If argument `tools_to_call_from` is passed, the model's tool calling options will be used to return a tool call.
@@ -329,7 +357,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> ChatCompletionOutputMessage:
+ ) -> ChatMessage:
messages = get_clean_message_list(
messages, role_conversions=tool_role_conversions
)
@@ -365,21 +393,21 @@ def __call__(
if stop_sequences is not None:
output = remove_stop_sequences(output, stop_sequences)
if tools_to_call_from is None:
- return ChatCompletionOutputMessage(role="assistant", content=output)
+ return ChatMessage(role="assistant", content=output)
else:
if "Action:" in output:
output = output.split("Action:", 1)[1].strip()
parsed_output = json.loads(output)
tool_name = parsed_output.get("tool_name")
tool_arguments = parsed_output.get("tool_arguments")
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="".join(random.choices("0123456789", k=5)),
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name=tool_name, arguments=tool_arguments
),
)
@@ -414,7 +442,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> ChatCompletionOutputMessage:
+ ) -> ChatMessage:
messages = get_clean_message_list(
messages, role_conversions=tool_role_conversions
)
@@ -485,7 +513,7 @@ def __call__(
grammar: Optional[str] = None,
max_tokens: int = 1500,
tools_to_call_from: Optional[List[Tool]] = None,
- ) -> ChatCompletionOutputMessage:
+ ) -> ChatMessage:
messages = get_clean_message_list(
messages, role_conversions=tool_role_conversions
)
diff --git a/src/smolagents/tools.py b/src/smolagents/tools.py
index d5ec6b0fe..04a203d92 100644
--- a/src/smolagents/tools.py
+++ b/src/smolagents/tools.py
@@ -221,6 +221,16 @@ def forward(self, *args, **kwargs):
def __call__(self, *args, sanitize_inputs_outputs: bool = False, **kwargs):
if not self.is_initialized:
self.setup()
+
+ # Handle the arguments might be passed as a single dictionary
+ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], dict):
+ potential_kwargs = args[0]
+
+ # If the dictionary keys match our input parameters, convert it to kwargs
+ if all(key in self.inputs for key in potential_kwargs):
+ args = ()
+ kwargs = potential_kwargs
+
if sanitize_inputs_outputs:
args, kwargs = handle_agent_input_types(*args, **kwargs)
outputs = self.forward(*args, **kwargs)
diff --git a/tests/test_agents.py b/tests/test_agents.py
index 38538cebc..1cd0a6750 100644
--- a/tests/test_agents.py
+++ b/tests/test_agents.py
@@ -30,10 +30,10 @@
from smolagents.default_tools import PythonInterpreterTool
from smolagents.tools import tool
from smolagents.types import AgentImage, AgentText
-from huggingface_hub import (
- ChatCompletionOutputMessage,
- ChatCompletionOutputToolCall,
- ChatCompletionOutputFunctionDefinition,
+from smolagents.models import (
+ ChatMessage,
+ ChatMessageToolCall,
+ ChatMessageToolCallDefinition,
)
@@ -47,28 +47,28 @@ def __call__(
self, messages, tools_to_call_from=None, stop_sequences=None, grammar=None
):
if len(messages) < 3:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_0",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="python_interpreter", arguments={"code": "2*3.6452"}
),
)
],
)
else:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_1",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="final_answer", arguments={"answer": "7.2904"}
),
)
@@ -81,14 +81,14 @@ def __call__(
self, messages, tools_to_call_from=None, stop_sequences=None, grammar=None
):
if len(messages) < 3:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_0",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="fake_image_generation_tool",
arguments={"prompt": "An image of a cat"},
),
@@ -96,14 +96,14 @@ def __call__(
],
)
else:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_1",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="final_answer", arguments="image.png"
),
)
@@ -114,7 +114,7 @@ def __call__(
def fake_code_model(messages, stop_sequences=None, grammar=None) -> str:
prompt = str(messages)
if "special_marker" not in prompt:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I should multiply 2 by 3.6452. special_marker
@@ -125,7 +125,7 @@ def fake_code_model(messages, stop_sequences=None, grammar=None) -> str:
""",
)
else: # We're at step 2
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I can now answer the initial question
@@ -140,7 +140,7 @@ def fake_code_model(messages, stop_sequences=None, grammar=None) -> str:
def fake_code_model_error(messages, stop_sequences=None) -> str:
prompt = str(messages)
if "special_marker" not in prompt:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I should multiply 2 by 3.6452. special_marker
@@ -154,7 +154,7 @@ def fake_code_model_error(messages, stop_sequences=None) -> str:
""",
)
else: # We're at step 2
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I can now answer the initial question
@@ -169,7 +169,7 @@ def fake_code_model_error(messages, stop_sequences=None) -> str:
def fake_code_model_syntax_error(messages, stop_sequences=None) -> str:
prompt = str(messages)
if "special_marker" not in prompt:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I should multiply 2 by 3.6452. special_marker
@@ -183,7 +183,7 @@ def fake_code_model_syntax_error(messages, stop_sequences=None) -> str:
""",
)
else: # We're at step 2
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I can now answer the initial question
@@ -196,7 +196,7 @@ def fake_code_model_syntax_error(messages, stop_sequences=None) -> str:
def fake_code_model_import(messages, stop_sequences=None) -> str:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I can answer the question
@@ -212,7 +212,7 @@ def fake_code_model_import(messages, stop_sequences=None) -> str:
def fake_code_functiondef(messages, stop_sequences=None) -> str:
prompt = str(messages)
if "special_marker" not in prompt:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: Let's define the function. special_marker
@@ -226,7 +226,7 @@ def moving_average(x, w):
""",
)
else: # We're at step 2
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I can now answer the initial question
@@ -241,7 +241,7 @@ def moving_average(x, w):
def fake_code_model_single_step(messages, stop_sequences=None, grammar=None) -> str:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I should multiply 2 by 3.6452. special_marker
@@ -255,7 +255,7 @@ def fake_code_model_single_step(messages, stop_sequences=None, grammar=None) ->
def fake_code_model_no_return(messages, stop_sequences=None, grammar=None) -> str:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: I should multiply 2 by 3.6452. special_marker
@@ -454,14 +454,14 @@ def __call__(
):
if tools_to_call_from is not None:
if len(messages) < 3:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_0",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="search_agent",
arguments="Who is the current US president?",
),
@@ -470,14 +470,14 @@ def __call__(
)
else:
assert "Report on the current US president" in str(messages)
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_0",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="final_answer", arguments="Final report."
),
)
@@ -485,7 +485,7 @@ def __call__(
)
else:
if len(messages) < 3:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: Let's call our search agent.
@@ -497,7 +497,7 @@ def __call__(
)
else:
assert "Report on the current US president" in str(messages)
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Thought: Let's return the report.
@@ -518,14 +518,14 @@ def __call__(
stop_sequences=None,
grammar=None,
):
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="call_0",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="final_answer",
arguments="Report on the current US president",
),
@@ -568,7 +568,7 @@ def __call__(
def test_code_nontrivial_final_answer_works(self):
def fake_code_model_final_answer(messages, stop_sequences=None, grammar=None):
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""Code:
```py
diff --git a/tests/test_default_tools.py b/tests/test_default_tools.py
new file mode 100644
index 000000000..d966b84a9
--- /dev/null
+++ b/tests/test_default_tools.py
@@ -0,0 +1,83 @@
+# coding=utf-8
+# Copyright 2024 HuggingFace Inc.
+#
+# 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.
+import unittest
+import pytest
+
+from smolagents.default_tools import PythonInterpreterTool, VisitWebpageTool
+from smolagents.types import AGENT_TYPE_MAPPING
+
+from .test_tools import ToolTesterMixin
+
+
+class DefaultToolTests(unittest.TestCase):
+ def test_visit_webpage(self):
+ arguments = {
+ "url": "https://en.wikipedia.org/wiki/United_States_Secretary_of_Homeland_Security"
+ }
+ result = VisitWebpageTool()(arguments)
+ assert isinstance(result, str)
+ assert (
+ "* [About Wikipedia](/wiki/Wikipedia:About)" in result
+ ) # Proper wikipedia pages have an About
+
+
+class PythonInterpreterToolTester(unittest.TestCase, ToolTesterMixin):
+ def setUp(self):
+ self.tool = PythonInterpreterTool(authorized_imports=["numpy"])
+ self.tool.setup()
+
+ def test_exact_match_arg(self):
+ result = self.tool("(2 / 2) * 4")
+ self.assertEqual(result, "Stdout:\n\nOutput: 4.0")
+
+ def test_exact_match_kwarg(self):
+ result = self.tool(code="(2 / 2) * 4")
+ self.assertEqual(result, "Stdout:\n\nOutput: 4.0")
+
+ def test_agent_type_output(self):
+ inputs = ["2 * 2"]
+ output = self.tool(*inputs, sanitize_inputs_outputs=True)
+ output_type = AGENT_TYPE_MAPPING[self.tool.output_type]
+ self.assertTrue(isinstance(output, output_type))
+
+ def test_agent_types_inputs(self):
+ inputs = ["2 * 2"]
+ _inputs = []
+
+ for _input, expected_input in zip(inputs, self.tool.inputs.values()):
+ input_type = expected_input["type"]
+ if isinstance(input_type, list):
+ _inputs.append(
+ [
+ AGENT_TYPE_MAPPING[_input_type](_input)
+ for _input_type in input_type
+ ]
+ )
+ else:
+ _inputs.append(AGENT_TYPE_MAPPING[input_type](_input))
+
+ # Should not raise an error
+ output = self.tool(*inputs, sanitize_inputs_outputs=True)
+ output_type = AGENT_TYPE_MAPPING[self.tool.output_type]
+ self.assertTrue(isinstance(output, output_type))
+
+ def test_imports_work(self):
+ result = self.tool("import numpy as np")
+ assert "import from numpy is not allowed" not in result.lower()
+
+ def test_unauthorized_imports_fail(self):
+ with pytest.raises(Exception) as e:
+ self.tool("import sympy as sp")
+ assert "sympy" in str(e).lower()
diff --git a/tests/test_monitoring.py b/tests/test_monitoring.py
index 11594e7ff..e55afb43d 100644
--- a/tests/test_monitoring.py
+++ b/tests/test_monitoring.py
@@ -23,9 +23,9 @@
stream_to_gradio,
)
from huggingface_hub import (
- ChatCompletionOutputMessage,
- ChatCompletionOutputToolCall,
- ChatCompletionOutputFunctionDefinition,
+ ChatMessage,
+ ChatMessageToolCall,
+ ChatMessageToolCallDefinition,
)
@@ -36,21 +36,21 @@ def __init__(self):
def __call__(self, prompt, tools_to_call_from=None, **kwargs):
if tools_to_call_from is not None:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="",
tool_calls=[
- ChatCompletionOutputToolCall(
+ ChatMessageToolCall(
id="fake_id",
type="function",
- function=ChatCompletionOutputFunctionDefinition(
+ function=ChatMessageToolCallDefinition(
name="final_answer", arguments={"answer": "image"}
),
)
],
)
else:
- return ChatCompletionOutputMessage(
+ return ChatMessage(
role="assistant",
content="""
Code:
@@ -91,9 +91,7 @@ def __init__(self):
self.last_output_token_count = 20
def __call__(self, prompt, **kwargs):
- return ChatCompletionOutputMessage(
- role="assistant", content="Malformed answer"
- )
+ return ChatMessage(role="assistant", content="Malformed answer")
agent = CodeAgent(
tools=[],
diff --git a/tests/test_python_interpreter.py b/tests/test_python_interpreter.py
index 8c7aacc9c..75a146e00 100644
--- a/tests/test_python_interpreter.py
+++ b/tests/test_python_interpreter.py
@@ -18,15 +18,12 @@
import numpy as np
import pytest
-from smolagents.default_tools import BASE_PYTHON_TOOLS, PythonInterpreterTool
+from smolagents.default_tools import BASE_PYTHON_TOOLS
from smolagents.local_python_executor import (
InterpreterError,
evaluate_python_code,
fix_final_answer_code,
)
-from smolagents.types import AGENT_TYPE_MAPPING
-
-from .test_tools import ToolTesterMixin
# Fake function we will use as tool
@@ -34,47 +31,6 @@ def add_two(x):
return x + 2
-class PythonInterpreterToolTester(unittest.TestCase, ToolTesterMixin):
- def setUp(self):
- self.tool = PythonInterpreterTool(authorized_imports=["sqlite3"])
- self.tool.setup()
-
- def test_exact_match_arg(self):
- result = self.tool("(2 / 2) * 4")
- self.assertEqual(result, "Stdout:\n\nOutput: 4.0")
-
- def test_exact_match_kwarg(self):
- result = self.tool(code="(2 / 2) * 4")
- self.assertEqual(result, "Stdout:\n\nOutput: 4.0")
-
- def test_agent_type_output(self):
- inputs = ["2 * 2"]
- output = self.tool(*inputs, sanitize_inputs_outputs=True)
- output_type = AGENT_TYPE_MAPPING[self.tool.output_type]
- self.assertTrue(isinstance(output, output_type))
-
- def test_agent_types_inputs(self):
- inputs = ["2 * 2"]
- _inputs = []
-
- for _input, expected_input in zip(inputs, self.tool.inputs.values()):
- input_type = expected_input["type"]
- if isinstance(input_type, list):
- _inputs.append(
- [
- AGENT_TYPE_MAPPING[_input_type](_input)
- for _input_type in input_type
- ]
- )
- else:
- _inputs.append(AGENT_TYPE_MAPPING[input_type](_input))
-
- # Should not raise an error
- output = self.tool(*inputs, sanitize_inputs_outputs=True)
- output_type = AGENT_TYPE_MAPPING[self.tool.output_type]
- self.assertTrue(isinstance(output, output_type))
-
-
class PythonInterpreterTester(unittest.TestCase):
def test_evaluate_assign(self):
code = "x = 3"
From 77f656c80d9995a3b28d1ecd1a12372766822994 Mon Sep 17 00:00:00 2001
From: Aggelos Kyriakoulis
Date: Tue, 14 Jan 2025 18:21:38 +0200
Subject: [PATCH 8/9] Implemented support for ast.Pass in the interpeter.
(#189)
---
src/smolagents/local_python_executor.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/smolagents/local_python_executor.py b/src/smolagents/local_python_executor.py
index 3c545cae6..7f1c67e94 100644
--- a/src/smolagents/local_python_executor.py
+++ b/src/smolagents/local_python_executor.py
@@ -1334,6 +1334,8 @@ def evaluate_ast(
if expression.value
else None
)
+ elif isinstance(expression, ast.Pass):
+ return None
else:
# For now we refuse anything else. Let's add things as we need them.
raise InterpreterError(f"{expression.__class__.__name__} is not supported.")
From ce1cd6d9066d2150ec6b5d72200f49e6171901f2 Mon Sep 17 00:00:00 2001
From: Aymeric Roucher <69208727+aymeric-roucher@users.noreply.github.com>
Date: Tue, 14 Jan 2025 19:27:07 +0100
Subject: [PATCH 9/9] Support pandas' iloc indexer (#191)
---
src/smolagents/local_python_executor.py | 3 +++
tests/test_python_interpreter.py | 16 ++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/src/smolagents/local_python_executor.py b/src/smolagents/local_python_executor.py
index 7f1c67e94..e54e0594c 100644
--- a/src/smolagents/local_python_executor.py
+++ b/src/smolagents/local_python_executor.py
@@ -685,6 +685,9 @@ def evaluate_subscript(
if isinstance(value, pd.core.indexing._LocIndexer):
parent_object = value.obj
return parent_object.loc[index]
+ if isinstance(value, pd.core.indexing._iLocIndexer):
+ parent_object = value.obj
+ return parent_object.iloc[index]
if isinstance(value, (pd.DataFrame, pd.Series, np.ndarray)):
return value[index]
elif isinstance(value, pd.core.groupby.generic.DataFrameGroupBy):
diff --git a/tests/test_python_interpreter.py b/tests/test_python_interpreter.py
index 75a146e00..58f250cfc 100644
--- a/tests/test_python_interpreter.py
+++ b/tests/test_python_interpreter.py
@@ -808,6 +808,7 @@ def test_pandas(self):
)
assert np.array_equal(result.values[0], [104, 1])
+ # Test groupby
code = """import pandas as pd
data = pd.DataFrame.from_dict([
{"Pclass": 1, "Survived": 1},
@@ -821,6 +822,21 @@ def test_pandas(self):
)
assert result.values[1] == 0.5
+ # Test loc and iloc
+ code = """import pandas as pd
+data = pd.DataFrame.from_dict([
+ {"Pclass": 1, "Survived": 1},
+ {"Pclass": 2, "Survived": 0},
+ {"Pclass": 2, "Survived": 1}
+])
+survival_rate_biased = data.loc[data['Survived']==1]['Survived'].mean()
+survival_rate_biased = data.loc[data['Survived']==1]['Survived'].mean()
+survival_rate_sorted = data.sort_values(by='Survived', ascending=False).iloc[0]
+"""
+ result, _ = evaluate_python_code(
+ code, {}, state={}, authorized_imports=["pandas"]
+ )
+
def test_starred(self):
code = """
from math import radians, sin, cos, sqrt, atan2