CultriX commited on
Commit
f060f46
·
1 Parent(s): 038f212
Files changed (6) hide show
  1. Dockerfile +0 -72
  2. __pycache__/run.cpython-312.pyc +0 -0
  3. app.py +89 -103
  4. requirements.txt +0 -2
  5. run.py +106 -283
  6. start.sh +0 -8
Dockerfile DELETED
@@ -1,72 +0,0 @@
1
- # Use a slim Python image for a smaller, faster build
2
- FROM python:3.12-slim
3
-
4
- # Set environment variables early (improves caching)
5
- ENV SEARXNG_URL="https://search.endorisk.nl" \
6
- SEARXNG_USERNAME="user" \
7
- SEARXNG_PASSWORD="password" \
8
- PATH="/home/user/.local/bin:$PATH"
9
-
10
- # 1) Install system dependencies
11
- RUN apt-get update -y && \
12
- apt-get install -y --no-install-recommends \
13
- git \
14
- ffmpeg \
15
- wget \
16
- curl \
17
- build-essential \
18
- tmux && \
19
- rm -rf /var/lib/apt/lists/*
20
-
21
- # 2) Install Node.js (required for MCP server)
22
- RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
23
- apt-get install -y --no-install-recommends nodejs && \
24
- rm -rf /var/lib/apt/lists/*
25
-
26
- # 3) Create a non-root user (uid 1000 is typical in Spaces)
27
- RUN useradd -m -u 1000 user
28
-
29
- WORKDIR /app
30
-
31
- # 4) Clone the repositories
32
- RUN git clone https://github.com/CultriX-Github/smolagents.git && \
33
- git clone https://github.com/ihor-sokoliuk/mcp-searxng.git
34
-
35
- # 5) Build the MCP server: install dependencies and build assets
36
- WORKDIR /app/mcp-searxng
37
- RUN echo "SEARXNG_USERNAME=user" > .env && \
38
- echo "SEARXNG_PASSWORD=password" >> .env && \
39
- cp .env /app/smolagents/examples/open_deep_research/.env && \
40
- npm install && \
41
- npm run build
42
-
43
- # 6) Install Python dependencies
44
- WORKDIR /app/smolagents/examples/open_deep_research
45
- # Copy the local requirements file into the container to trigger caching if unchanged
46
- COPY requirements.txt .
47
- RUN pip install --no-cache-dir --upgrade pip && \
48
- pip install --no-cache-dir -r requirements.txt --break-system-packages && \
49
- pip install --no-cache-dir mcp --break-system-packages && \
50
- pip install --no-cache-dir 'smolagents[litellm, mcp]' --break-system-packages
51
-
52
- # 7) Create the downloads directory and fix permissions
53
- RUN mkdir -p downloads && \
54
- chown -R user:user /app/smolagents/examples/open_deep_research && \
55
- chown -R user:user /app/mcp-searxng
56
-
57
- # 8) Copy the custom startup and application files
58
- COPY start.sh .
59
- COPY app.py .
60
- COPY run.py .
61
-
62
- # 9) Ensure the startup script is executable
63
- RUN chmod +x start.sh
64
-
65
- # 10) Switch to the non-root user for runtime
66
- USER user
67
-
68
- # 11) Expose Gradio's default port
69
- EXPOSE 7860
70
-
71
- # 12) Set the default command to run the startup script
72
- ENTRYPOINT ["python", "app.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
__pycache__/run.cpython-312.pyc CHANGED
Binary files a/__pycache__/run.cpython-312.pyc and b/__pycache__/run.cpython-312.pyc differ
 
app.py CHANGED
@@ -1,108 +1,94 @@
1
- import os
2
  import gradio as gr
3
- from run import create_agent, log_formatter, MODEL_CONFIGS
4
- import io
5
- import logging
6
- import contextlib
7
-
8
- # Simple dark theme styling.
9
- CSS = """
10
- body {
11
- background-color: #2c2c2c;
12
- color: #ffffff;
13
- }
14
- .gradio-container {
15
- background-color: #3a3a3a;
16
- border-radius: 10px;
17
- padding: 20px;
18
- }
19
- h1, h2, h3 {
20
- color: #79c0ff;
21
- }
22
- """
23
-
24
- def set_keys(openai_api_key, serper_api_key, hf_token, gemini_api_key, groq_api_key):
25
- os.environ["OPENAI_API_KEY"] = openai_api_key
26
- os.environ["SERPER_API_KEY"] = serper_api_key
27
- os.environ["HF_TOKEN"] = hf_token
28
- os.environ["GEMINI_API_KEY"] = gemini_api_key
29
- os.environ["GROQ_API_KEY"] = groq_api_key
30
- return "API keys have been updated successfully! Please restart the agent for changes to take effect."
31
-
32
- def get_answer(question, model_name):
33
- log_buffer = io.StringIO()
34
- stdout_buffer = io.StringIO()
35
- stream_handler = logging.StreamHandler(log_buffer)
36
- stream_handler.setFormatter(log_formatter)
37
- root_logger = logging.getLogger()
38
- root_logger.setLevel(logging.DEBUG)
39
- root_logger.addHandler(stream_handler)
40
-
41
- conversation = []
42
- try:
43
- agent = create_agent(model_name=model_name)
44
- answer = agent.run(question)
45
- if isinstance(answer, str):
46
- conversation = [
47
- {"role": "user", "content": question},
48
- {"role": "assistant", "content": answer}
49
- ]
50
- else:
51
- result = ""
52
- for chunk in answer:
53
- result += chunk
54
- conversation = [
55
- {"role": "user", "content": question},
56
- {"role": "assistant", "content": result}
57
- ]
58
- except Exception as e:
59
- conversation = [
60
- {"role": "user", "content": question},
61
- {"role": "assistant", "content": f"An error occurred: {e}"}
62
- ]
63
- finally:
64
- root_logger.removeHandler(stream_handler)
65
- stream_handler.close()
66
- logs = log_buffer.getvalue()
67
- return conversation, f"```\n{stdout_buffer.getvalue()}\n{logs}\n```"
68
-
69
- def build_app():
70
- with gr.Blocks(css=CSS) as demo:
71
- # Title and header.
72
- gr.HTML("<h1>SmolAgents Open Deep Search 🥳</h1>")
73
- gr.Markdown("## Enhanced Agent UI")
74
-
75
- # Configuration Accordion.
76
- with gr.Accordion("Configuration (Click to Expand)", open=False):
77
- openai_field = gr.Textbox(label="OPENAI_API_KEY", type="password", placeholder="Enter your OpenAI API key")
78
- serper_field = gr.Textbox(label="SERPER_API_KEY", type="password", placeholder="Enter your Serper API key")
79
- hf_field = gr.Textbox(label="HF_TOKEN", type="password", placeholder="Enter your Hugging Face Token")
80
- gemini_field = gr.Textbox(label="GEMINI_API_KEY", type="password", placeholder="Enter your Gemini API key")
81
- groq_field = gr.Textbox(label="GROQ_API_KEY", type="password", placeholder="Enter your Groq API key")
82
- update_btn = gr.Button("Update Keys")
83
- status_box = gr.Markdown("*(No keys set yet)*")
84
- update_btn.click(fn=set_keys, inputs=[openai_field, serper_field, hf_field, gemini_field, groq_field], outputs=status_box)
85
-
86
- # Placeholder for agent logs.
87
- log_markdown = gr.Markdown(label="Agent Logs")
88
-
89
- gr.Markdown("### Select a model and ask your question below:")
90
- model_names = list(MODEL_CONFIGS.keys())
91
- model_dropdown = gr.Dropdown(choices=model_names, label="Select Model", value="o1", allow_custom_value=True)
92
- question_input = gr.Textbox(label="Your Question", placeholder="Enter your question here...")
93
- submit_btn = gr.Button("Get Answer")
94
- # Use Chatbot component with type "messages" for OpenAI-style dict format.
95
- chatbot = gr.Chatbot(label="Answer", type="messages")
96
-
97
- # Connect the answer function.
98
- submit_btn.click(
99
- fn=get_answer,
100
- inputs=[question_input, model_dropdown],
101
- outputs=[chatbot, log_markdown]
102
  )
103
 
104
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  if __name__ == "__main__":
107
- demo = build_app()
108
- demo.launch(server_name="0.0.0.0")
 
1
+ from run import create_agent
2
  import gradio as gr
3
+ import os
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+ CONFIG_FILE = ".user_config.env"
8
+
9
+ def save_env_vars_to_file(env_vars):
10
+ print("[DEBUG] Saving user config to file")
11
+ with open(CONFIG_FILE, "w") as f:
12
+ for key, value in env_vars.items():
13
+ f.write(f"{key}={value}\n")
14
+
15
+ def launch_interface():
16
+ def setup_agent(question, model_id, hf_token, serpapi_key, use_custom_endpoint,
17
+ custom_api_endpoint, custom_api_key, search_provider, search_api_key, custom_search_url):
18
+ print("[DEBUG] Setting up agent with input question:", question)
19
+
20
+ if question.strip() == "":
21
+ return "Please enter a question."
22
+
23
+ endpoint = custom_api_endpoint if use_custom_endpoint else None
24
+ api_key = custom_api_key if use_custom_endpoint else None
25
+
26
+ save_env_vars_to_file({
27
+ "HF_TOKEN": hf_token,
28
+ "SERPAPI_API_KEY": serpapi_key,
29
+ })
30
+
31
+ print("[DEBUG] Instantiating agent with UI configuration")
32
+ agent = create_agent(
33
+ model_id=model_id,
34
+ hf_token=hf_token,
35
+ serpapi_key=serpapi_key,
36
+ custom_api_endpoint=endpoint,
37
+ custom_api_key=api_key,
38
+ search_provider=search_provider,
39
+ search_api_key=search_api_key,
40
+ custom_search_url=custom_search_url
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  )
42
 
43
+ return agent.run(question)
44
+
45
+ with gr.Blocks(theme=gr.themes.Base(), css=".gr-box { border-radius: 15px; padding: 20px; }") as demo:
46
+ gr.Markdown("# 🤖 SmolAgent Configurable Interface")
47
+
48
+ with gr.Row():
49
+ with gr.Column(scale=2):
50
+ question = gr.Textbox(label="🧠 Question", placeholder="Ask me anything...")
51
+ model_id = gr.Textbox(value="gpt-4o-mini", label="🧬 Model ID")
52
+ hf_token = gr.Textbox(value=os.getenv("HF_TOKEN", ""), label="🔑 HuggingFace Token", type="password")
53
+ serpapi_key = gr.Textbox(value=os.getenv("SERPAPI_API_KEY", ""), label="🔍 Serper API Key", type="password", visible=True)
54
+ use_custom_endpoint = gr.Checkbox(label="🌐 Use Custom API Endpoint")
55
+ custom_api_endpoint = gr.Textbox(label="🔌 Custom API Endpoint URL", placeholder="https://your-api-endpoint.com", visible=False)
56
+ custom_api_key = gr.Textbox(label="🔐 Custom API Endpoint Key", type="password", visible=False)
57
+ search_provider = gr.Dropdown(label="🔎 Search Provider", choices=["serper", "searxng"], value="serper")
58
+ search_api_key = gr.Textbox(label="🔑 Search Provider API Key (optional)", type="password", visible=False)
59
+ custom_search_url = gr.Textbox(label="🌐 Custom SearxNG Instance URL", placeholder="https://your-searxng-instance/search", visible=False)
60
+ submit_btn = gr.Button("🚀 Run Agent")
61
+ with gr.Column(scale=1):
62
+ output = gr.Textbox(label="📤 Answer", lines=15)
63
+
64
+ def update_search_visibility(provider):
65
+ return {
66
+ serpapi_key: gr.update(visible=(provider == "serper")),
67
+ custom_search_url: gr.update(visible=(provider == "searxng")),
68
+ search_api_key: gr.update(visible=(provider == "searxng")),
69
+ }
70
+
71
+ def update_custom_endpoint_visibility(checked):
72
+ return {
73
+ custom_api_endpoint: gr.update(visible=checked),
74
+ custom_api_key: gr.update(visible=checked),
75
+ }
76
+
77
+ search_provider.change(fn=update_search_visibility, inputs=search_provider,
78
+ outputs=[serpapi_key, custom_search_url, search_api_key])
79
+
80
+ use_custom_endpoint.change(fn=update_custom_endpoint_visibility, inputs=use_custom_endpoint,
81
+ outputs=[custom_api_endpoint, custom_api_key])
82
+
83
+ submit_btn.click(fn=setup_agent,
84
+ inputs=[question, model_id, hf_token, serpapi_key,
85
+ use_custom_endpoint, custom_api_endpoint, custom_api_key,
86
+ search_provider, search_api_key, custom_search_url],
87
+ outputs=output)
88
+
89
+ print("[DEBUG] Launching Gradio interface")
90
+ demo.launch()
91
 
92
  if __name__ == "__main__":
93
+ launch_interface()
94
+
requirements.txt CHANGED
@@ -1,5 +1,3 @@
1
- gradio
2
- uvicorn
3
  dotenv
4
  anthropic>=0.37.1
5
  audioop-lts<1.0; python_version >= "3.13" # required to use pydub in Python >=3.13; LTS port of the removed Python builtin module audioop
 
 
 
1
  dotenv
2
  anthropic>=0.37.1
3
  audioop-lts<1.0; python_version >= "3.13" # required to use pydub in Python >=3.13; LTS port of the removed Python builtin module audioop
run.py CHANGED
@@ -1,6 +1,7 @@
1
  import argparse
2
  import os
3
- import logging
 
4
  from dotenv import load_dotenv
5
  from huggingface_hub import login
6
  from scripts.text_inspector_tool import TextInspectorTool
@@ -14,285 +15,86 @@ from scripts.text_web_browser import (
14
  VisitTool,
15
  )
16
  from scripts.visual_qa import visualizer
 
17
  from smolagents import (
18
  CodeAgent,
19
- DuckDuckGoSearchTool,
20
- LiteLLMModel,
21
  ToolCallingAgent,
 
 
 
22
  )
23
 
24
- # Initialize logging
25
- logger = logging.getLogger("smolagents")
26
- logger.setLevel(logging.INFO)
27
- log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
28
-
29
- # Load environment variables
30
- load_dotenv(override=True)
31
-
32
- hf_token = os.getenv("HF_TOKEN")
33
- if hf_token:
34
- login(hf_token)
35
- logger.info("Logged into Hugging Face Hub.")
36
- else:
37
- logger.warning("HF_TOKEN not found. Proceeding without authentication.")
38
-
39
  AUTHORIZED_IMPORTS = [
40
- "requests", "zipfile", "os", "pandas", "numpy", "sympy", "json", "bs4",
41
  "pubchempy", "xml", "yahoo_finance", "Bio", "sklearn", "scipy", "pydub",
42
- "io", "PIL", "chess", "PyPDF2", "pptx", "torch", "datetime", "fractions", "csv", "string", "secrets",
43
  ]
44
 
45
- USER_AGENT = (
46
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
47
- "AppleWebKit/537.36 (KHTML, like Gecko) "
48
- "Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
49
- )
50
-
51
- BROWSER_CONFIG = {
52
- "viewport_size": 5120,
53
- "downloads_folder": "downloads_folder",
54
- "request_kwargs": {
55
- "headers": {"User-Agent": USER_AGENT},
56
- "timeout": 150,
57
- "max_retries": 2,
58
- },
59
- "serpapi_key": os.getenv("SERPAPI_API_KEY"),
60
- }
61
 
62
- os.makedirs(f"./{BROWSER_CONFIG['downloads_folder']}", exist_ok=True)
63
 
64
- custom_role_conversions = {"tool-call": "assistant", "tool-response": "user"}
 
 
 
 
 
 
 
 
 
 
65
 
66
- # Define the model configurations (custom models intact)
67
- MODEL_CONFIGS = {
68
- # OPENAI MODELS
69
- "gpt-3.5-turbo": {
70
- "litellm_params": {
71
- "model_id": "openai/gpt-3.5-turbo",
72
- "api_key": os.getenv("OPENAI_API_KEY"),
73
- "custom_role_conversions": custom_role_conversions,
74
- "max_completion_tokens": 8192,
75
- },
76
- },
77
- "gpt-3.5-turbo-16k": {
78
- "litellm_params": {
79
- "model_id": "openai/gpt-3.5-turbo-16k",
80
- "api_key": os.getenv("OPENAI_API_KEY"),
81
- "custom_role_conversions": custom_role_conversions,
82
- "max_completion_tokens": 16384,
83
- },
84
- },
85
- "gpt-4o-mini": {
86
- "litellm_params": {
87
- "model_id": "openai/gpt-4o-mini",
88
- "api_key": os.getenv("OPENAI_API_KEY"),
89
- "custom_role_conversions": custom_role_conversions,
90
- "max_completion_tokens": 8192,
91
- },
92
- },
93
- "chatgpt-4o-latest": {
94
- "litellm_params": {
95
- "model_id": "openai/chatgpt-4o-latest",
96
- "api_key": os.getenv("OPENAI_API_KEY"),
97
- "custom_role_conversions": custom_role_conversions,
98
- "max_completion_tokens": 8192,
99
- },
100
- },
101
- "gpt-4-turbo": {
102
- "litellm_params": {
103
- "model_id": "openai/gpt-4-turbo",
104
- "api_key": os.getenv("OPENAI_API_KEY"),
105
- "custom_role_conversions": custom_role_conversions,
106
- "max_completion_tokens": 8192,
107
- },
108
- },
109
- "gpt-4o": {
110
- "litellm_params": {
111
- "model_id": "openai/gpt-4o",
112
- "api_key": os.getenv("OPENAI_API_KEY"),
113
- "custom_role_conversions": custom_role_conversions,
114
- "max_completion_tokens": 8192,
115
- },
116
- },
117
- "o1-mini": {
118
- "litellm_params": {
119
- "model_id": "openai/o1-mini",
120
- "api_key": os.getenv("OPENAI_API_KEY"),
121
- "custom_role_conversions": custom_role_conversions,
122
- "max_completion_tokens": 8192,
123
- "reasoning_effort": "high",
124
- },
125
- },
126
- "o1-preview": {
127
- "litellm_params": {
128
- "model_id": "openai/o1-preview",
129
- "api_key": os.getenv("OPENAI_API_KEY"),
130
- "custom_role_conversions": custom_role_conversions,
131
- "max_completion_tokens": 8192,
132
- "reasoning_effort": "high",
133
- },
134
- },
135
- # HUGGINGFACE MODELS
136
- "hf-llama-3.1-8B-instruct": {
137
- "litellm_params": {
138
- "model_id": "huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct",
139
- "api_key": os.getenv("HF_TOKEN"),
140
- "custom_role_conversions": custom_role_conversions,
141
- "max_completion_tokens": 8192,
142
- },
143
- },
144
- "hf-DeepSeek-R1-Distill-Qwen-32B": {
145
- "litellm_params": {
146
- "model_id": "huggingface/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
147
- "api_key": os.getenv("HF_TOKEN"),
148
- "custom_role_conversions": custom_role_conversions,
149
- "max_completion_tokens": 8192,
150
- },
151
- },
152
- "hf-Qwen2.5-Coder-32B-Instruct": {
153
- "litellm_params": {
154
- "model_id": "huggingface/Qwen/Qwen2.5-Coder-32B-Instruct",
155
- "api_key": os.getenv("HF_TOKEN"),
156
- "custom_role_conversions": custom_role_conversions,
157
- "max_completion_tokens": 8192,
158
- },
159
- },
160
- "hf-QwQ-32B-Preview": {
161
- "litellm_params": {
162
- "model_id": "huggingface/Qwen/QwQ-32B-Preview",
163
- "api_key": os.getenv("HF_TOKEN"),
164
- "custom_role_conversions": custom_role_conversions,
165
- "max_completion_tokens": 8192,
166
- },
167
- },
168
- "hf-Llama-3.1-70B-Instruct": {
169
- "litellm_params": {
170
- "model_id": "huggingface/meta-llama/Llama-3.1-70B-Instruct",
171
- "api_key": os.getenv("HF_TOKEN"),
172
- "custom_role_conversions": custom_role_conversions,
173
- "max_completion_tokens": 8192,
174
- },
175
- },
176
- # GROQ MODELS
177
- "groq-llama3-8b-8192": {
178
- "litellm_params": {
179
- "model_id": "groq/llama3-8b-8192",
180
- "api_key": os.getenv("GROQ_API_KEY"),
181
- "custom_role_conversions": custom_role_conversions,
182
- "max_completion_tokens": 8192,
183
- },
184
- },
185
- "groq-llama3-70b-8192": {
186
- "litellm_params": {
187
- "model_id": "groq/llama3-70b-8192",
188
- "api_key": os.getenv("GROQ_API_KEY"),
189
- "custom_role_conversions": custom_role_conversions,
190
- "max_completion_tokens": 8192,
191
- },
192
- },
193
- "groq-mixtral-8x7b-32768": {
194
- "litellm_params": {
195
- "model_id": "groq/mixtral-8x7b-32768",
196
- "api_key": os.getenv("GROQ_API_KEY"),
197
- "custom_role_conversions": custom_role_conversions,
198
- "max_completion_tokens": 32768,
199
- },
200
- },
201
- # GEMINI MODELS
202
- "gemini-pro": {
203
- "litellm_params": {
204
- "model_id": "gemini/gemini-pro",
205
- "api_key": os.getenv("GEMINI_API_KEY"),
206
- "custom_role_conversions": custom_role_conversions,
207
- "max_completion_tokens": 8192,
208
- },
209
- },
210
- "gemini-1.5-pro": {
211
- "litellm_params": {
212
- "model_id": "gemini/gemini-1.5-pro",
213
- "api_key": os.getenv("GEMINI_API_KEY"),
214
- "custom_role_conversions": custom_role_conversions,
215
- "max_completion_tokens": 8192,
216
- },
217
- },
218
- "gemini-1.5-flash": {
219
- "litellm_params": {
220
- "model_id": "gemini/gemini-1.5-flash",
221
- "api_key": os.getenv("GEMINI_API_KEY"),
222
- "custom_role_conversions": custom_role_conversions,
223
- "max_completion_tokens": 8192,
224
- },
225
- },
226
- "gemini-pro-vision": {
227
- "litellm_params": {
228
- "model_id": "gemini/gemini-pro-vision",
229
- "api_key": os.getenv("GEMINI_API_KEY"),
230
- "custom_role_conversions": custom_role_conversions,
231
- "max_completion_tokens": 8192,
232
- },
233
- },
234
- "gemini-2.0-flash": {
235
- "litellm_params": {
236
- "model_id": "gemini/gemini-2.0-flash",
237
- "api_key": os.getenv("GEMINI_API_KEY"),
238
- "custom_role_conversions": custom_role_conversions,
239
- "max_completion_tokens": 8192,
240
- },
241
- },
242
- "gemini-2.0-flash-thinking-exp-01-21": {
243
- "litellm_params": {
244
- "model_id": "gemini/gemini-2.0-flash-thinking-exp-01-21",
245
- "api_key": os.getenv("GEMINI_API_KEY"),
246
- "custom_role_conversions": custom_role_conversions,
247
- "max_completion_tokens": 8192,
248
- },
249
- },
250
- # Default o1 model
251
- "o1": {
252
- "litellm_params": {
253
- "model_id": "o1",
254
- "custom_role_conversions": custom_role_conversions,
255
- "max_completion_tokens": 8192,
256
- "reasoning_effort": "high",
257
- },
258
- },
259
- }
260
 
261
- def parse_args():
262
- parser = argparse.ArgumentParser(
263
- description="Run the search agent to answer questions using web browsing tools."
264
- )
265
- parser.add_argument(
266
- "question",
267
- type=str,
268
- help="Example: 'How many studio albums did Mercedes Sosa release before 2007?'"
269
- )
270
- parser.add_argument(
271
- "--model-id",
272
- type=str,
273
- default="o1",
274
- help="Model identifier (default: o1)"
275
- )
276
- return parser.parse_args()
277
 
278
- def create_agent(model_name="o1"):
279
- if model_name not in MODEL_CONFIGS:
280
- raise ValueError(f"Model '{model_name}' is not a valid model. Available models are: {list(MODEL_CONFIGS.keys())}")
281
 
282
- model_params = MODEL_CONFIGS[model_name]["litellm_params"]
283
- model_params.setdefault("custom_role_conversions", custom_role_conversions)
284
- model_params.setdefault("max_completion_tokens", 8192)
285
- # (Optional: adjust parameters here to lower temperature for more factual answers.)
286
 
287
  model = LiteLLMModel(**model_params)
288
- logger.info(f"Initialized LiteLLMModel with model_name={model_name}")
289
- text_limit = 100000
290
 
291
- browser = SimpleTextBrowser(**BROWSER_CONFIG)
292
- logger.info("Initialized SimpleTextBrowser with custom configuration.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
  WEB_TOOLS = [
295
- DuckDuckGoSearchTool(),
296
  VisitTool(browser),
297
  PageUpTool(browser),
298
  PageDownTool(browser),
@@ -301,49 +103,70 @@ def create_agent(model_name="o1"):
301
  ArchiveSearchTool(browser),
302
  TextInspectorTool(model, text_limit),
303
  ]
304
- logger.info("Initialized web tools for ToolCallingAgent.")
305
 
306
  text_webbrowser_agent = ToolCallingAgent(
307
  model=model,
308
  tools=WEB_TOOLS,
309
- max_steps=10,
310
- verbosity_level=2,
311
  planning_interval=4,
312
  name="search_agent",
313
- description=(
314
- "A team member that will search the internet to answer your question. "
315
- "Ask all questions that require browsing the web using complete sentences. "
316
- "Provide as much context as possible, especially if searching within a specific timeframe."
317
- ),
318
  provide_run_summary=True,
319
  )
320
- logger.info("Initialized ToolCallingAgent.")
 
 
 
321
 
322
  manager_agent = CodeAgent(
323
  model=model,
324
  tools=[visualizer, TextInspectorTool(model, text_limit)],
325
- max_steps=12,
326
- verbosity_level=2,
327
  additional_authorized_imports=AUTHORIZED_IMPORTS,
328
  planning_interval=4,
329
  managed_agents=[text_webbrowser_agent],
330
  )
331
- logger.info("Initialized Manager CodeAgent.")
 
332
  return manager_agent
333
 
 
334
  def main():
335
- args = parse_args()
336
- logger.info(f"Received question: {args.question} with model_id={args.model_id}")
337
- agent = create_agent(model_name=args.model_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  answer = agent.run(args.question)
339
- if isinstance(answer, str):
340
- print(f"Got this answer: {answer}")
341
- else:
342
- result = ""
343
- for chunk in answer:
344
- result += chunk
345
- print(f"Got this answer: {result}")
346
- logger.info("Agent has completed processing the question.")
347
 
348
  if __name__ == "__main__":
349
  main()
 
 
1
  import argparse
2
  import os
3
+ import threading
4
+
5
  from dotenv import load_dotenv
6
  from huggingface_hub import login
7
  from scripts.text_inspector_tool import TextInspectorTool
 
15
  VisitTool,
16
  )
17
  from scripts.visual_qa import visualizer
18
+
19
  from smolagents import (
20
  CodeAgent,
 
 
21
  ToolCallingAgent,
22
+ LiteLLMModel,
23
+ DuckDuckGoSearchTool,
24
+ Tool,
25
  )
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  AUTHORIZED_IMPORTS = [
28
+ "shell_gpt", "sgpt", "openai", "requests", "zipfile", "os", "pandas", "numpy", "sympy", "json", "bs4",
29
  "pubchempy", "xml", "yahoo_finance", "Bio", "sklearn", "scipy", "pydub",
30
+ "yaml", "string", "secrets", "io", "PIL", "chess", "PyPDF2", "pptx", "torch", "datetime", "fractions", "csv",
31
  ]
32
 
33
+ append_answer_lock = threading.Lock()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
 
35
 
36
+ def create_agent(
37
+ model_id="gpt-4o-mini",
38
+ hf_token=None,
39
+ serpapi_key=None,
40
+ custom_api_endpoint=None,
41
+ custom_api_key=None,
42
+ search_provider="serper",
43
+ search_api_key=None,
44
+ custom_search_url=None
45
+ ):
46
+ print("[DEBUG] Creating agent with model_id:", model_id)
47
 
48
+ if hf_token:
49
+ print("[DEBUG] Logging into HuggingFace")
50
+ login(hf_token)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ model_params = {
53
+ "model_id": model_id,
54
+ "custom_role_conversions": {"tool-call": "assistant", "tool-response": "user"},
55
+ "max_completion_tokens": 8192,
56
+ }
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ if model_id == "gpt-4o-mini":
59
+ model_params["reasoning_effort"] = "high"
 
60
 
61
+ if custom_api_endpoint and custom_api_key:
62
+ print("[DEBUG] Using custom API endpoint:", custom_api_endpoint)
63
+ model_params["base_url"] = custom_api_endpoint
64
+ model_params["api_key"] = custom_api_key
65
 
66
  model = LiteLLMModel(**model_params)
67
+ print("[DEBUG] Model initialized")
 
68
 
69
+ text_limit = 100000
70
+ user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
71
+
72
+ browser_config = {
73
+ "viewport_size": 1024 * 5,
74
+ "downloads_folder": "downloads_folder",
75
+ "request_kwargs": {
76
+ "headers": {"User-Agent": user_agent},
77
+ "timeout": 300,
78
+ },
79
+ "serpapi_key": serpapi_key,
80
+ }
81
+
82
+ os.makedirs(f"./{browser_config['downloads_folder']}", exist_ok=True)
83
+ browser = SimpleTextBrowser(**browser_config)
84
+ print("[DEBUG] Browser initialized")
85
+
86
+ # Correct tool selection
87
+ if search_provider == "searxng":
88
+ print("[DEBUG] Using SearxNG-compatible DuckDuckGoSearchTool with base_url override")
89
+ search_tool = DuckDuckGoSearchTool()
90
+ if custom_search_url:
91
+ search_tool.base_url = custom_search_url # Override default DuckDuckGo URL (only if supported)
92
+ else:
93
+ print("[DEBUG] Using default DuckDuckGoSearchTool for Serper/standard search")
94
+ search_tool = DuckDuckGoSearchTool()
95
 
96
  WEB_TOOLS = [
97
+ search_tool,
98
  VisitTool(browser),
99
  PageUpTool(browser),
100
  PageDownTool(browser),
 
103
  ArchiveSearchTool(browser),
104
  TextInspectorTool(model, text_limit),
105
  ]
 
106
 
107
  text_webbrowser_agent = ToolCallingAgent(
108
  model=model,
109
  tools=WEB_TOOLS,
110
+ max_steps=20,
111
+ verbosity_level=3,
112
  planning_interval=4,
113
  name="search_agent",
114
+ description="A team member that will search the internet to answer your question.",
 
 
 
 
115
  provide_run_summary=True,
116
  )
117
+
118
+ text_webbrowser_agent.prompt_templates["managed_agent"]["task"] += """You can navigate to .txt online files.
119
+ If a non-html page is in another format, especially .pdf or a Youtube video, use tool 'inspect_file_as_text' to inspect it.
120
+ Additionally, if after some searching you find out that you need more information to answer the question, you can use `final_answer` with your request for clarification as argument to request for more information."""
121
 
122
  manager_agent = CodeAgent(
123
  model=model,
124
  tools=[visualizer, TextInspectorTool(model, text_limit)],
125
+ max_steps=16,
126
+ verbosity_level=3,
127
  additional_authorized_imports=AUTHORIZED_IMPORTS,
128
  planning_interval=4,
129
  managed_agents=[text_webbrowser_agent],
130
  )
131
+
132
+ print("[DEBUG] Agent fully initialized")
133
  return manager_agent
134
 
135
+
136
  def main():
137
+ print("[DEBUG] Loading environment variables")
138
+ load_dotenv(override=True)
139
+
140
+ parser = argparse.ArgumentParser()
141
+ parser.add_argument("question", type=str)
142
+ parser.add_argument("--model-id", type=str, default="gpt-4o-mini")
143
+ parser.add_argument("--hf-token", type=str, default=os.getenv("HF_TOKEN"))
144
+ parser.add_argument("--serpapi-key", type=str, default=os.getenv("SERPAPI_API_KEY"))
145
+ parser.add_argument("--custom-api-endpoint", type=str, default=None)
146
+ parser.add_argument("--custom-api-key", type=str, default=None)
147
+ parser.add_argument("--search-provider", type=str, default="serper")
148
+ parser.add_argument("--search-api-key", type=str, default=None)
149
+ parser.add_argument("--custom-search-url", type=str, default=None)
150
+ args = parser.parse_args()
151
+
152
+ print("[DEBUG] CLI arguments parsed:", args)
153
+
154
+ agent = create_agent(
155
+ model_id=args.model_id,
156
+ hf_token=args.hf_token,
157
+ serpapi_key=args.serpapi_key,
158
+ custom_api_endpoint=args.custom_api_endpoint,
159
+ custom_api_key=args.custom_api_key,
160
+ search_provider=args.search_provider,
161
+ search_api_key=args.search_api_key,
162
+ custom_search_url=args.custom_search_url,
163
+ )
164
+
165
+ print("[DEBUG] Running agent...")
166
  answer = agent.run(args.question)
167
+ print(f"Got this answer: {answer}")
168
+
 
 
 
 
 
 
169
 
170
  if __name__ == "__main__":
171
  main()
172
+
start.sh DELETED
@@ -1,8 +0,0 @@
1
- #!/bin/bash
2
- # Exit immediately if a command exits with a non-zero status.
3
- set -e
4
-
5
- echo "Starting Gradio UI with enhanced performance optimizations..."
6
- cd /app/smolagents/examples/open_deep_research
7
- /bin/bash -c "python app.py &"
8
- exec "$@"