tinyagent-py 0.0.12__py3-none-any.whl → 0.0.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Dict, List, Any, Optional
3
3
  from tinyagent.hooks.logging_manager import LoggingManager
4
+ import cloudpickle
4
5
 
5
6
 
6
7
  class CodeExecutionProvider(ABC):
@@ -69,8 +70,6 @@ class CodeExecutionProvider(ABC):
69
70
  Args:
70
71
  tools: List of tool objects to add
71
72
  """
72
- import cloudpickle
73
-
74
73
  tools_str_list = ["import cloudpickle"]
75
74
  tools_str_list.append("###########<tools>###########\n")
76
75
  for tool in tools:
@@ -82,6 +81,22 @@ class CodeExecutionProvider(ABC):
82
81
  tools_str_list.append("\n\n")
83
82
  self.code_tools_definitions.extend(tools_str_list)
84
83
 
84
+ def set_code_tools(self, tools: List[Any]) -> None:
85
+ """
86
+ Set the code tools available in the execution environment.
87
+ Replaces any existing tools with the new list.
88
+
89
+ Args:
90
+ tools: List of tool objects to set
91
+ """
92
+ # Clear existing tools
93
+ self.code_tools = tools.copy()
94
+ self.code_tools_definitions = []
95
+
96
+ # Add the new tools
97
+ if tools:
98
+ self.add_tools(tools)
99
+
85
100
  def set_user_variables(self, variables: Dict[str, Any]) -> None:
86
101
  """
87
102
  Set user variables that will be available in the Python environment.
@@ -89,8 +104,6 @@ class CodeExecutionProvider(ABC):
89
104
  Args:
90
105
  variables: Dictionary of variable name -> value pairs
91
106
  """
92
- import cloudpickle
93
-
94
107
  self._user_variables = variables.copy()
95
108
 
96
109
  # Add variables to the execution environment by serializing them
@@ -149,4 +162,46 @@ class CodeExecutionProvider(ABC):
149
162
  Returns:
150
163
  Dictionary of current user variables
151
164
  """
152
- return self._user_variables.copy()
165
+ return self._user_variables.copy()
166
+
167
+ def update_user_variables_from_globals(self, globals_dict: Dict[str, Any]) -> None:
168
+ """
169
+ Extract and update user variables from the globals dictionary after code execution.
170
+ This ensures that any modifications to user variables during code execution are preserved.
171
+
172
+ Args:
173
+ globals_dict: The globals dictionary after code execution
174
+ """
175
+ if not globals_dict or not self._user_variables:
176
+ return
177
+
178
+ # Update user variables with values from globals
179
+ for var_name in list(self._user_variables.keys()):
180
+ if var_name in globals_dict:
181
+ try:
182
+ # Try to serialize the value to ensure it's valid
183
+ cloudpickle.dumps(globals_dict[var_name])
184
+ # Update the user variable with the new value
185
+ self._user_variables[var_name] = globals_dict[var_name]
186
+ except Exception:
187
+ # If serialization fails, keep the old value
188
+ pass
189
+
190
+ # Check for new variables that might have been created
191
+ # This handles cases where LLM creates new variables that should be preserved
192
+ for var_name, var_value in globals_dict.items():
193
+ # Skip special variables, modules, and functions
194
+ if (var_name.startswith('__') or
195
+ var_name in ['builtins', 'cloudpickle'] or
196
+ callable(var_value) or
197
+ var_name in self._user_variables):
198
+ continue
199
+
200
+ try:
201
+ # Try to serialize the value to ensure it's valid
202
+ cloudpickle.dumps(var_value)
203
+ # Add the new variable to user variables
204
+ self._user_variables[var_name] = var_value
205
+ except Exception:
206
+ # If serialization fails, skip this variable
207
+ pass
@@ -143,17 +143,28 @@ class ModalProvider(CodeExecutionProvider):
143
143
  print(full_code)
144
144
  print("#" * 100)
145
145
 
146
-
147
146
 
148
147
  # Use Modal's native execution methods
149
148
  response = self._python_executor(full_code, self._globals_dict, self._locals_dict)
150
149
 
151
150
  print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<response>!!!!!!!!!!!!!!!!!!!!!!!!!")
152
151
 
153
- # Update the instance globals and locals with the execution results
154
- self._globals_dict = cloudpickle.loads(make_session_blob(response["updated_globals"]))
155
- self._locals_dict = cloudpickle.loads(make_session_blob(response["updated_locals"]))
156
-
152
+ # Always update globals and locals dictionaries, regardless of whether there was an error
153
+ # This ensures variables are preserved even when code execution fails
154
+ try:
155
+ # Update globals and locals from the response
156
+ if "updated_globals" in response:
157
+ self._globals_dict = cloudpickle.loads(make_session_blob(response["updated_globals"]))
158
+
159
+ if "updated_locals" in response:
160
+ self._locals_dict = cloudpickle.loads(make_session_blob(response["updated_locals"]))
161
+
162
+ # Update user variables from the updated globals and locals
163
+ # This preserves any changes made to variables by the LLM
164
+ self.update_user_variables_from_globals(self._globals_dict)
165
+ self.update_user_variables_from_globals(self._locals_dict)
166
+ except Exception as e:
167
+ print(f"Warning: Failed to update globals/locals after execution: {str(e)}")
157
168
 
158
169
  self._log_response(response)
159
170
 
@@ -261,7 +261,16 @@ class TinyCodeAgent:
261
261
  async def run_python(code_lines: List[str], timeout: int = 120) -> str:
262
262
  """Execute Python code using the configured provider."""
263
263
  try:
264
+ # Before execution, ensure provider has the latest user variables
265
+ if self.user_variables:
266
+ self.code_provider.set_user_variables(self.user_variables)
267
+
264
268
  result = await self.code_provider.execute_python(code_lines, timeout)
269
+
270
+ # After execution, update TinyCodeAgent's user_variables from the provider
271
+ # This ensures they stay in sync
272
+ self.user_variables = self.code_provider.get_user_variables()
273
+
265
274
  return str(result)
266
275
  except Exception as e:
267
276
  print("!"*100)
@@ -272,6 +281,11 @@ class TinyCodeAgent:
272
281
  print(f"{COLOR['RED']}{str(e)}{COLOR['ENDC']}")
273
282
  print(f"{COLOR['RED']}{traceback.format_exc()}{COLOR['ENDC']}")
274
283
  print("!"*100)
284
+
285
+ # Even after an exception, update user_variables from the provider
286
+ # This ensures any variables that were successfully created/modified are preserved
287
+ self.user_variables = self.code_provider.get_user_variables()
288
+
275
289
  return f"Error executing code: {str(e)}"
276
290
 
277
291
  self.agent.add_tool(run_python)
@@ -116,22 +116,34 @@ def _run_python(
116
116
  #updated_globals['print'] = custom_print
117
117
 
118
118
  # Parse the code
119
- tree = ast.parse(code, mode="exec")
120
- compiled = compile(tree, filename="<ast>", mode="exec")
119
+ try:
120
+ tree = ast.parse(code, mode="exec")
121
+ compiled = compile(tree, filename="<ast>", mode="exec")
122
+ except SyntaxError as e:
123
+ # Return syntax error without executing
124
+ return {
125
+ "printed_output": "",
126
+ "return_value": None,
127
+ "stderr": "",
128
+ "error_traceback": f"Syntax error: {str(e)}",
129
+ "updated_globals": updated_globals,
130
+ "updated_locals": updated_locals
131
+ }
132
+
121
133
  stdout_buf = io.StringIO()
122
134
  stderr_buf = io.StringIO()
123
135
  # Execute with exception handling
124
136
  error_traceback = None
125
137
  output = None
126
138
 
139
+ # Merge all variables into globals to avoid scoping issues with generator expressions
140
+ # When exec() is called with both globals and locals, generator expressions can't
141
+ # access local variables. By using only globals, everything runs in global scope.
142
+ merged_globals = updated_globals.copy()
143
+ merged_globals.update(updated_locals)
144
+
127
145
  with contextlib.redirect_stdout(stdout_buf), contextlib.redirect_stderr(stderr_buf):
128
146
  try:
129
- # Merge all variables into globals to avoid scoping issues with generator expressions
130
- # When exec() is called with both globals and locals, generator expressions can't
131
- # access local variables. By using only globals, everything runs in global scope.
132
- merged_globals = updated_globals.copy()
133
- merged_globals.update(updated_locals)
134
-
135
147
  # Add 'exec' to authorized_functions for internal use
136
148
  internal_authorized_functions = ['exec','eval']
137
149
  if authorized_functions is not None and not isinstance(authorized_functions, bool):
@@ -152,6 +164,18 @@ def _run_python(
152
164
  except Exception:
153
165
  # Capture the full traceback as a string
154
166
  error_traceback = traceback.format_exc()
167
+
168
+ # CRITICAL FIX: Even when an exception occurs, we need to update the globals and locals
169
+ # with any variables that were successfully created/modified before the exception
170
+ for key, value in merged_globals.items():
171
+ # Skip special variables and modules
172
+ if key.startswith('__') or key in ['builtins', 'traceback', 'contextlib', 'io', 'ast', 'sys']:
173
+ continue
174
+
175
+ # Update both dictionaries with the current state
176
+ if key in updated_locals or key not in updated_globals:
177
+ updated_locals[key] = value
178
+ updated_globals[key] = value
155
179
 
156
180
  # Join all captured output
157
181
  #printed_output = ''.join(output_buffer)
@@ -845,8 +845,9 @@ class GradioCallback:
845
845
 
846
846
  # Footer
847
847
  gr.Markdown(
848
- "<div style='text-align: center; margin-top: 20px;'>"
849
- "Powered by <a href='https://github.com/askbudi/tinyagent' target='_blank'>TinyAgent</a>"
848
+ "<div style='text-align: center; margin-top: 20px;'>"
849
+ "Built with ❤️ by <a href='https://github.com/askbudi/tinyagent' target='_blank'>TinyAgent</a>"
850
+ "<br>Start building your own AI agents with TinyAgent"
850
851
  "</div>"
851
852
  )
852
853
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinyagent-py
3
- Version: 0.0.12
3
+ Version: 0.0.13
4
4
  Summary: TinyAgent with MCP Client, Code Agent (Thinking, Planning, and Executing in Python), and Extendable Hooks, Tiny but powerful
5
5
  Author-email: Mahdi Golchin <golchin@askdev.ai>
6
6
  Project-URL: Homepage, https://github.com/askbudi/tinyagent
@@ -60,6 +60,16 @@ Inspired by:
60
60
  ## Quick Links
61
61
  - [Build your own Tiny Agent](https://askdev.ai/github/askbudi/tinyagent)
62
62
 
63
+
64
+ ## Live Projects using TinyAgent (🔥)
65
+ - [AskDev.AI](https://askdev.ai) - Understand, chat, and summarize codebase of any project on GitHub.
66
+ - [HackBuddy AI](https://huggingface.co/spaces/ask-dev/HackBuddyAI) - A Hackathon Assistant Agent, built with TinyCodeAgent and Gradio. Match invdividuals to teams based on their skills, interests and organizer preferences.
67
+
68
+ - [TinyCodeAgent Demo](https://huggingface.co/spaces/ask-dev/TinyCodeAgent) - A playground for TinyCodeAgent, built with tinyagent, Gradio and Modal.com
69
+
70
+ ** Building something with TinyAgent? Let us know and I'll add it here!**
71
+
72
+
63
73
  ## Overview
64
74
  This is a tiny agent framework that uses MCP and LiteLLM to interact with language models. You have full control over the agent, you can add any tools you like from MCP and extend the agent using its event system.
65
75
 
@@ -7,15 +7,15 @@ tinyagent/code_agent/example.py,sha256=qC6i3auUT1YwXS9WK1Ovq-9oDOUgzRxDegYdlVcVc
7
7
  tinyagent/code_agent/helper.py,sha256=oZnpo-_H3cB12LxNN7Ztd-31EiUcuI2UpWP69xuF8oE,7205
8
8
  tinyagent/code_agent/modal_sandbox.py,sha256=RcQ5a-UFyqV7xSHnttpgAQQ-mNWk-9Z0tb836ua7C0E,16381
9
9
  tinyagent/code_agent/safety.py,sha256=WHad2ypzfsdKnXG6FcgXcgGiMC-H4KTmOzhP9S9i3Zw,22209
10
- tinyagent/code_agent/tiny_code_agent.py,sha256=r3c_irn5RJp9qNewhlOLFaGGTAjLWqHjTwM8QewN54I,27426
11
- tinyagent/code_agent/utils.py,sha256=CAg8LKc_sxnXmwF0L2nRP13XsftYl3ZiD5qWO5D7QeQ,6842
10
+ tinyagent/code_agent/tiny_code_agent.py,sha256=UrNjmJSrDC493bXGARrt0tDd1Bn56FgNlxuQSu4J614,28194
11
+ tinyagent/code_agent/utils.py,sha256=FxHnpb06S2o2-xPRHgf9zAnzbXvGWs5QApNI4DEH__U,7870
12
12
  tinyagent/code_agent/providers/__init__.py,sha256=myfy9qsBDjNOhcgXJ2E9jO1q5eo6jHp43I2k0k8esLY,136
13
- tinyagent/code_agent/providers/base.py,sha256=Hm8jrD60QovgQHTwiFE1pKDHPk1cwGbUdzuSwic9Rjc,5832
14
- tinyagent/code_agent/providers/modal_provider.py,sha256=4uhmDA2pLYbbBi3actrBkHD_-pt3gt2incKBj12hab0,10084
13
+ tinyagent/code_agent/providers/base.py,sha256=LfmahpulNbnivn5m91GTAo6ityjidq05dC3qx9EtJ80,8203
14
+ tinyagent/code_agent/providers/modal_provider.py,sha256=R0qt8XlTMFMbznMHN32pQxupDE9KR18NpQ3l1wJJP0w,10799
15
15
  tinyagent/code_agent/tools/__init__.py,sha256=0XtrgYBgBayOffW50KyrlmrXXs9iu6z1DHu7-D8WGqY,94
16
16
  tinyagent/code_agent/tools/example_tools.py,sha256=YbXb7PKuvvxh-LV12Y4n_Ez3RyLA95gWOcZrKsa7UHg,1203
17
17
  tinyagent/hooks/__init__.py,sha256=RZow2r0XHLJ3-tnmecScdc0_wrEdmOy5dtXqoiRME5Y,254
18
- tinyagent/hooks/gradio_callback.py,sha256=3vKfGknn7XOHtcoF6DkLKDCJmC_oCRhu1-kqWmAAOc4,56821
18
+ tinyagent/hooks/gradio_callback.py,sha256=78x2x9AbYoLV-qwCxn2sH4s39DLlhNCzL7qCkVR-vy4,56911
19
19
  tinyagent/hooks/logging_manager.py,sha256=UpdmpQ7HRPyer-jrmQSXcBwi409tV9LnGvXSHjTcYTI,7935
20
20
  tinyagent/hooks/rich_code_ui_callback.py,sha256=PLcu5MOSoP4oZR3BtvcV9DquxcIT_d0WzSlkvaDcGOk,19820
21
21
  tinyagent/hooks/rich_ui_callback.py,sha256=5iCNOiJmhc1lOL7ZjaOt5Sk3rompko4zu_pAxfTVgJQ,22897
@@ -26,8 +26,8 @@ tinyagent/storage/json_file_storage.py,sha256=SYD8lvTHu2-FEHm1tZmsrcgEOirBrlUsUM
26
26
  tinyagent/storage/postgres_storage.py,sha256=IGwan8UXHNnTZFK1F8x4kvMDex3GAAGWUg9ePx_5IF4,9018
27
27
  tinyagent/storage/redis_storage.py,sha256=hu3y7wHi49HkpiR-AW7cWVQuTVOUk1WaB8TEPGUKVJ8,1742
28
28
  tinyagent/storage/sqlite_storage.py,sha256=ZyOYe0d_oHO1wOIT8FxKIbc67tP_0e_8FnM2Zq8Pwj8,5915
29
- tinyagent_py-0.0.12.dist-info/licenses/LICENSE,sha256=YIogcVQnknaaE4K-oaQylFWo8JGRBWnwmGb3fWB_Pww,1064
30
- tinyagent_py-0.0.12.dist-info/METADATA,sha256=Q05U9Z6UJNPoHtmAbpMzxB2HfcnQbGOHHz3W1EfgWt0,13250
31
- tinyagent_py-0.0.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- tinyagent_py-0.0.12.dist-info/top_level.txt,sha256=Ny8aJNchZpc2Vvhp3306L5vjceJakvFxBk-UjjVeA_I,10
33
- tinyagent_py-0.0.12.dist-info/RECORD,,
29
+ tinyagent_py-0.0.13.dist-info/licenses/LICENSE,sha256=YIogcVQnknaaE4K-oaQylFWo8JGRBWnwmGb3fWB_Pww,1064
30
+ tinyagent_py-0.0.13.dist-info/METADATA,sha256=qr6akWcOHEZNUtQ34H_XalRWtJD-mK6WLiwmlcTH_N0,13848
31
+ tinyagent_py-0.0.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
+ tinyagent_py-0.0.13.dist-info/top_level.txt,sha256=Ny8aJNchZpc2Vvhp3306L5vjceJakvFxBk-UjjVeA_I,10
33
+ tinyagent_py-0.0.13.dist-info/RECORD,,