gemini-agent-framework 0.1.1__py3-none-any.whl → 0.1.3__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.
- gemini_agent/agent.py +112 -8
- {gemini_agent_framework-0.1.1.dist-info → gemini_agent_framework-0.1.3.dist-info}/METADATA +1 -1
- gemini_agent_framework-0.1.3.dist-info/RECORD +5 -0
- gemini_agent_framework-0.1.1.dist-info/RECORD +0 -5
- {gemini_agent_framework-0.1.1.dist-info → gemini_agent_framework-0.1.3.dist-info}/WHEEL +0 -0
gemini_agent/agent.py
CHANGED
@@ -4,6 +4,7 @@ import inspect
|
|
4
4
|
from functools import wraps
|
5
5
|
from typing import List, Callable, Dict, Any, Optional
|
6
6
|
from dotenv import load_dotenv
|
7
|
+
from datetime import datetime
|
7
8
|
|
8
9
|
load_dotenv()
|
9
10
|
|
@@ -31,6 +32,7 @@ class Agent:
|
|
31
32
|
Agent._tools_registry[func.__name__]['description'] = desc
|
32
33
|
Agent._tools_registry[func.__name__]['signature'] = inspect.signature(func)
|
33
34
|
Agent._tools_registry[func.__name__]['function_ref'] = func
|
35
|
+
Agent._tools_registry[func.__name__]['is_method'] = inspect.ismethod(func)
|
34
36
|
@wraps(func)
|
35
37
|
def wrapper(*args, **kwargs):
|
36
38
|
return func(*args, **kwargs)
|
@@ -48,6 +50,7 @@ class Agent:
|
|
48
50
|
Agent._tools_registry[func.__name__]['signature'] = inspect.signature(func)
|
49
51
|
if 'function_ref' not in Agent._tools_registry[func.__name__]:
|
50
52
|
Agent._tools_registry[func.__name__]['function_ref'] = func
|
53
|
+
Agent._tools_registry[func.__name__]['is_method'] = inspect.ismethod(func)
|
51
54
|
@wraps(func)
|
52
55
|
def wrapper(*args, **kwargs):
|
53
56
|
return func(*args, **kwargs)
|
@@ -60,7 +63,7 @@ class Agent:
|
|
60
63
|
|
61
64
|
Args:
|
62
65
|
api_key: Your Google Generative AI API key.
|
63
|
-
tools: A list of Python functions decorated as tools.
|
66
|
+
tools: A list of Python functions or class methods decorated as tools.
|
64
67
|
model_name: The name of the Gemini model to use.
|
65
68
|
"""
|
66
69
|
if not api_key:
|
@@ -72,7 +75,9 @@ class Agent:
|
|
72
75
|
|
73
76
|
self._registered_tools_json: List[Dict[str, Any]] = [] # Store JSON representation
|
74
77
|
self._tool_functions: Dict[str, Callable] = {} # Map name to actual function
|
78
|
+
self._tool_instances: Dict[str, Any] = {} # Store instances for class methods
|
75
79
|
self._intermediate_results: Dict[str, Any] = {} # Store intermediate results
|
80
|
+
self._stored_variables: Dict[str, Dict[str, Any]] = {} # Store variables with metadata
|
76
81
|
|
77
82
|
if tools:
|
78
83
|
self._process_tools(tools)
|
@@ -90,6 +95,12 @@ class Agent:
|
|
90
95
|
print(f"Warning: Function '{tool_name}' is missing @Agent.description. Skipping.")
|
91
96
|
continue
|
92
97
|
|
98
|
+
# Store the bound method directly if it's a class method
|
99
|
+
if inspect.ismethod(func):
|
100
|
+
self._tool_functions[tool_name] = func
|
101
|
+
else:
|
102
|
+
self._tool_functions[tool_name] = metadata['function_ref']
|
103
|
+
|
93
104
|
# Build the parameters schema JSON
|
94
105
|
gemini_params_schema = {
|
95
106
|
"type": "OBJECT",
|
@@ -102,6 +113,9 @@ class Agent:
|
|
102
113
|
if not params_def and signature:
|
103
114
|
params_def = {}
|
104
115
|
for name, param in signature.parameters.items():
|
116
|
+
# Skip 'self' parameter for class methods
|
117
|
+
if name == 'self' and inspect.ismethod(func):
|
118
|
+
continue
|
105
119
|
py_type = param.annotation if param.annotation != inspect.Parameter.empty else str
|
106
120
|
params_def[name] = {'type': py_type, 'description': f'Parameter {name}'}
|
107
121
|
|
@@ -125,10 +139,53 @@ class Agent:
|
|
125
139
|
del declaration_json["parameters"]
|
126
140
|
|
127
141
|
self._registered_tools_json.append(declaration_json)
|
128
|
-
|
142
|
+
|
143
|
+
def set_variable(self, name: str, value: Any, description: str = "", type_hint: type = None) -> None:
|
144
|
+
"""
|
145
|
+
Stores a variable in the agent's memory with metadata.
|
146
|
+
|
147
|
+
Args:
|
148
|
+
name: The name of the variable
|
149
|
+
value: The actual value to store
|
150
|
+
description: A description of what the variable represents
|
151
|
+
type_hint: Optional type hint for the variable
|
152
|
+
"""
|
153
|
+
self._stored_variables[name] = {
|
154
|
+
'value': value,
|
155
|
+
'description': description,
|
156
|
+
'type': type_hint or type(value).__name__,
|
157
|
+
'created_at': datetime.now().isoformat()
|
158
|
+
}
|
159
|
+
|
160
|
+
def get_variable(self, name: str) -> Any:
|
161
|
+
"""
|
162
|
+
Retrieves a stored variable's value.
|
163
|
+
|
164
|
+
Args:
|
165
|
+
name: The name of the variable to retrieve
|
166
|
+
|
167
|
+
Returns:
|
168
|
+
The stored value or None if not found
|
169
|
+
"""
|
170
|
+
return self._stored_variables.get(name, {}).get('value')
|
171
|
+
|
172
|
+
def list_variables(self) -> Dict[str, Dict[str, Any]]:
|
173
|
+
"""
|
174
|
+
Returns information about all stored variables.
|
175
|
+
|
176
|
+
Returns:
|
177
|
+
Dictionary of variable names to their metadata
|
178
|
+
"""
|
179
|
+
return {name: {k: v for k, v in data.items() if k != 'value'}
|
180
|
+
for name, data in self._stored_variables.items()}
|
129
181
|
|
130
182
|
def _get_system_prompt(self) -> str:
|
131
183
|
"""Returns a system prompt that guides the model in breaking down complex operations."""
|
184
|
+
variables_info = "\n".join([
|
185
|
+
f"- {name}: {data['description']} (Type: {data['type']})"
|
186
|
+
for name, data in self._stored_variables.items()
|
187
|
+
])
|
188
|
+
|
132
189
|
return """You are an AI assistant that can break down complex tasks into sequential steps using available tools.
|
133
190
|
When faced with a complex request:
|
134
191
|
1. Analyze the request to identify which tools can be used
|
@@ -141,13 +198,49 @@ class Agent:
|
|
141
198
|
Available tools:
|
142
199
|
{tools_list}
|
143
200
|
|
201
|
+
Available variables:
|
202
|
+
{variables_list}
|
203
|
+
|
204
|
+
IMPORTANT - Variable Usage:
|
205
|
+
When you need to use a stored variable in a function call, you MUST use the following syntax:
|
206
|
+
- For function arguments: {{"variable": "variable_name"}}
|
207
|
+
- For example, if you want to use the 'current_user' variable in a function call:
|
208
|
+
{{"user_id": {{"variable": "current_user"}}}}
|
209
|
+
|
144
210
|
Remember:
|
145
211
|
- Always perform one operation at a time
|
146
212
|
- Use intermediate results from previous steps
|
147
213
|
- If a step requires multiple tools, execute them sequentially
|
148
214
|
- If you're unsure about the next step, explain your reasoning
|
149
|
-
|
150
|
-
|
215
|
+
- You can use both stored variables and values from the prompt
|
216
|
+
- When using stored variables, ALWAYS use the {{"variable": "variable_name"}} syntax
|
217
|
+
""".format(
|
218
|
+
tools_list="\n".join([f"- {name}: {desc}" for name, desc in
|
219
|
+
[(tool['name'], tool['description']) for tool in self._registered_tools_json]]),
|
220
|
+
variables_list=variables_info
|
221
|
+
)
|
222
|
+
|
223
|
+
def _substitute_variables(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
224
|
+
"""
|
225
|
+
Substitutes stored variable values in function arguments.
|
226
|
+
|
227
|
+
Args:
|
228
|
+
args: Dictionary of argument names to values
|
229
|
+
|
230
|
+
Returns:
|
231
|
+
Dictionary with variable values substituted where applicable
|
232
|
+
"""
|
233
|
+
substituted_args = {}
|
234
|
+
for name, value in args.items():
|
235
|
+
if isinstance(value, dict) and "variable" in value:
|
236
|
+
var_name = value["variable"]
|
237
|
+
if var_name in self._stored_variables:
|
238
|
+
substituted_args[name] = self._stored_variables[var_name]['value']
|
239
|
+
else:
|
240
|
+
substituted_args[name] = value
|
241
|
+
else:
|
242
|
+
substituted_args[name] = value
|
243
|
+
return substituted_args
|
151
244
|
|
152
245
|
def _call_gemini_api(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
153
246
|
"""Makes a POST request to the Gemini generateContent endpoint."""
|
@@ -192,14 +285,14 @@ class Agent:
|
|
192
285
|
self._intermediate_results = {}
|
193
286
|
|
194
287
|
if not system_prompt:
|
195
|
-
system_prompt = self._get_system_prompt() + system_prompt
|
196
|
-
else:
|
197
288
|
system_prompt = self._get_system_prompt()
|
289
|
+
else:
|
290
|
+
system_prompt = self._get_system_prompt() + system_prompt
|
198
291
|
|
199
292
|
current_contents = conversation_history if conversation_history else []
|
200
293
|
if system_prompt and not current_contents:
|
201
294
|
current_contents.append({'role': 'user', 'parts': [{'text': system_prompt}]})
|
202
|
-
current_contents.append({'role': 'model', 'parts': [{'text': "I understand I should break down complex tasks into sequential steps using the available tools."}]})
|
295
|
+
current_contents.append({'role': 'model', 'parts': [{'text': "I understand I should break down complex tasks into sequential steps using the available tools and variables."}]})
|
203
296
|
|
204
297
|
current_contents.append({'role': 'user', 'parts': [{'text': user_prompt}]})
|
205
298
|
payload: Dict[str, Any] = {"contents": current_contents}
|
@@ -214,6 +307,14 @@ class Agent:
|
|
214
307
|
|
215
308
|
if response_structure and not self._registered_tools_json:
|
216
309
|
apply_structure_later = False
|
310
|
+
# If response_structure is a string type, make it more flexible
|
311
|
+
if response_structure.get("type") == "string":
|
312
|
+
response_structure = {
|
313
|
+
"type": ["string", "object"],
|
314
|
+
"properties": {
|
315
|
+
"value": {"type": "string"}
|
316
|
+
}
|
317
|
+
}
|
217
318
|
payload["generationConfig"] = {
|
218
319
|
"response_mime_type": "application/json",
|
219
320
|
"response_schema": response_structure
|
@@ -223,7 +324,6 @@ class Agent:
|
|
223
324
|
|
224
325
|
while True:
|
225
326
|
response_data = self._call_gemini_api(payload)
|
226
|
-
|
227
327
|
if "error" in response_data:
|
228
328
|
print(f"API call failed: {response_data['error'].get('message', 'Unknown API error')}")
|
229
329
|
return response_data
|
@@ -266,13 +366,17 @@ class Agent:
|
|
266
366
|
tool_function = self._tool_functions[tool_name]
|
267
367
|
print(f"--- Calling Function: {tool_name}({args}) ---")
|
268
368
|
|
369
|
+
# Substitute both stored variables and intermediate results
|
370
|
+
args = self._substitute_variables(args)
|
269
371
|
for key, value in args.items():
|
270
372
|
if isinstance(value, str) and value.startswith('$'):
|
271
373
|
result_key = value[1:]
|
272
374
|
if result_key in self._intermediate_results:
|
273
375
|
args[key] = self._intermediate_results[result_key]
|
274
376
|
|
377
|
+
# Call the function directly - it's already bound if it's a method
|
275
378
|
function_result = tool_function(**args)
|
379
|
+
|
276
380
|
print(f"--- Function Result: {function_result} ---")
|
277
381
|
|
278
382
|
result_key = f"result_{len(self._intermediate_results)}"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gemini-agent-framework
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: A framework for building agents that use Gemini's function calling capabilities
|
5
5
|
Project-URL: Homepage, https://github.com/m7mdony/gemini-agent-framework
|
6
6
|
Project-URL: Documentation, https://github.com/m7mdony/gemini-agent-framework#readme
|
@@ -0,0 +1,5 @@
|
|
1
|
+
gemini_agent/__init__.py,sha256=2AgrBW0ePFgOvwoNNqRcZaMPdbOaKPoNHXUo_VlFX-M,71
|
2
|
+
gemini_agent/agent.py,sha256=_jHx3ELxP2XmHPDiPqZs_1nH2OPdK8p_8AvLwlUGrz8,24045
|
3
|
+
gemini_agent_framework-0.1.3.dist-info/METADATA,sha256=DPXkQScmKbTIT4QYqDh4U5iVFFiwy7R1IKzcwRI3R3c,2386
|
4
|
+
gemini_agent_framework-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
+
gemini_agent_framework-0.1.3.dist-info/RECORD,,
|
@@ -1,5 +0,0 @@
|
|
1
|
-
gemini_agent/__init__.py,sha256=2AgrBW0ePFgOvwoNNqRcZaMPdbOaKPoNHXUo_VlFX-M,71
|
2
|
-
gemini_agent/agent.py,sha256=DqbUBsiI3qzEVAeKAMvlTp0yC0HuK8RAgpmxIJWbPYM,19552
|
3
|
-
gemini_agent_framework-0.1.1.dist-info/METADATA,sha256=glzOEjvwQP2wswyz_NPzPjdQYfaMOooDCMU3ewbGMBs,2386
|
4
|
-
gemini_agent_framework-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
-
gemini_agent_framework-0.1.1.dist-info/RECORD,,
|
File without changes
|