gemini-agent-framework 0.1.2__tar.gz → 0.1.3__tar.gz

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,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemini-agent-framework
3
- Version: 0.1.2
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "gemini-agent-framework"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "A framework for building agents that use Gemini's function calling capabilities"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1,4 @@
1
+ from .agent import Agent
2
+
3
+ __version__ = "0.1.1"
4
+ __all__ = ["Agent"]
@@ -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
 
@@ -76,6 +77,7 @@ class Agent:
76
77
  self._tool_functions: Dict[str, Callable] = {} # Map name to actual function
77
78
  self._tool_instances: Dict[str, Any] = {} # Store instances for class methods
78
79
  self._intermediate_results: Dict[str, Any] = {} # Store intermediate results
80
+ self._stored_variables: Dict[str, Dict[str, Any]] = {} # Store variables with metadata
79
81
 
80
82
  if tools:
81
83
  self._process_tools(tools)
@@ -138,8 +140,52 @@ class Agent:
138
140
 
139
141
  self._registered_tools_json.append(declaration_json)
140
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()}
181
+
141
182
  def _get_system_prompt(self) -> str:
142
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
+
143
189
  return """You are an AI assistant that can break down complex tasks into sequential steps using available tools.
144
190
  When faced with a complex request:
145
191
  1. Analyze the request to identify which tools can be used
@@ -152,13 +198,49 @@ class Agent:
152
198
  Available tools:
153
199
  {tools_list}
154
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
+
155
210
  Remember:
156
211
  - Always perform one operation at a time
157
212
  - Use intermediate results from previous steps
158
213
  - If a step requires multiple tools, execute them sequentially
159
214
  - If you're unsure about the next step, explain your reasoning
160
- """.format(tools_list="\n".join([f"- {name}: {desc}" for name, desc in
161
- [(tool['name'], tool['description']) for tool in self._registered_tools_json]]))
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
162
244
 
163
245
  def _call_gemini_api(self, payload: Dict[str, Any]) -> Dict[str, Any]:
164
246
  """Makes a POST request to the Gemini generateContent endpoint."""
@@ -210,7 +292,7 @@ class Agent:
210
292
  current_contents = conversation_history if conversation_history else []
211
293
  if system_prompt and not current_contents:
212
294
  current_contents.append({'role': 'user', 'parts': [{'text': system_prompt}]})
213
- 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."}]})
214
296
 
215
297
  current_contents.append({'role': 'user', 'parts': [{'text': user_prompt}]})
216
298
  payload: Dict[str, Any] = {"contents": current_contents}
@@ -242,7 +324,6 @@ class Agent:
242
324
 
243
325
  while True:
244
326
  response_data = self._call_gemini_api(payload)
245
-
246
327
  if "error" in response_data:
247
328
  print(f"API call failed: {response_data['error'].get('message', 'Unknown API error')}")
248
329
  return response_data
@@ -285,6 +366,8 @@ class Agent:
285
366
  tool_function = self._tool_functions[tool_name]
286
367
  print(f"--- Calling Function: {tool_name}({args}) ---")
287
368
 
369
+ # Substitute both stored variables and intermediate results
370
+ args = self._substitute_variables(args)
288
371
  for key, value in args.items():
289
372
  if isinstance(value, str) and value.startswith('$'):
290
373
  result_key = value[1:]
@@ -0,0 +1,3 @@
1
+ """
2
+ Test package for the Gemini Agent Framework.
3
+ """
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from dotenv import load_dotenv
3
- from gemini_agent import Agent
3
+ from framework_agent import Agent
4
4
 
5
5
  load_dotenv()
6
6
 
@@ -0,0 +1,133 @@
1
+ from agent import Agent
2
+ import os
3
+ from dotenv import load_dotenv
4
+ import json
5
+ from bs4 import BeautifulSoup
6
+
7
+ load_dotenv()
8
+
9
+ class HTMLAnalyzer:
10
+ @Agent.description("Count the number of input tags in an HTML page")
11
+ @Agent.parameters({
12
+ 'html_content': {'type': str, 'description': 'The HTML content to analyze'}
13
+ })
14
+ def count_inputs(self, html_content: str) -> dict:
15
+ soup = BeautifulSoup(html_content, 'html.parser')
16
+ input_tags = soup.find_all('input')
17
+ return {
18
+ "count": len(input_tags),
19
+ "input_types": [tag.get('type', 'unknown') for tag in input_tags]
20
+ }
21
+
22
+ # Create HTML pages
23
+ home_page = """
24
+ <!DOCTYPE html>
25
+ <html>
26
+ <head>
27
+ <title>Home Page</title>
28
+ </head>
29
+ <body>
30
+ <header>
31
+ <nav>
32
+ <a href="/">Home</a>
33
+ <a href="/about">About</a>
34
+ <a href="/contact">Contact</a>
35
+ </nav>
36
+ </header>
37
+ <main>
38
+ <h1>Welcome to Our Website</h1>
39
+ <p>This is a simple home page with no input fields.</p>
40
+ </main>
41
+ <footer>
42
+ <p>&copy; 2024 Our Website</p>
43
+ </footer>
44
+ </body>
45
+ </html>
46
+ """
47
+
48
+ login_page = """
49
+ <!DOCTYPE html>
50
+ <html>
51
+ <head>
52
+ <title>Login Page</title>
53
+ </head>
54
+ <body>
55
+ <header>
56
+ <nav>
57
+ <a href="/">Home</a>
58
+ <a href="/login">Login</a>
59
+ </nav>
60
+ </header>
61
+ <main>
62
+ <h1>Login</h1>
63
+ <form action="/login" method="POST">
64
+ <div>
65
+ <label for="username">Username:</label>
66
+ <input type="text" id="username" name="username" required>
67
+ </div>
68
+ <div>
69
+ <label for="password">Password:</label>
70
+ <input type="password" id="password" name="password" required>
71
+ </div>
72
+ <div>
73
+ <input type="checkbox" id="remember" name="remember">
74
+ <label for="remember">Remember me</label>
75
+ </div>
76
+ <button type="submit">Login</button>
77
+ </form>
78
+ </main>
79
+ <footer>
80
+ <p>&copy; 2024 Our Website</p>
81
+ </footer>
82
+ </body>
83
+ </html>
84
+ """
85
+
86
+ # Create the analyzer instance
87
+ html_analyzer = HTMLAnalyzer()
88
+
89
+ # Create the agent with our tool
90
+ agent = Agent(
91
+ api_key=os.getenv("GEMINI_API_KEY"),
92
+ tools=[html_analyzer.count_inputs]
93
+ )
94
+
95
+ # Store the HTML pages as variables
96
+ agent.set_variable(
97
+ name="home_page",
98
+ value=home_page,
99
+ description="The HTML content of the home page",
100
+ type_hint=str
101
+ )
102
+
103
+
104
+
105
+ # Example 1: Count inputs in home page
106
+ print("\nExample 1: Count inputs in home page")
107
+ response = agent.prompt(
108
+ "How many input tags are in the home page?",
109
+ response_structure={
110
+ "type": "object",
111
+ "properties": {
112
+ "count": {"type": "integer"},
113
+ "input_types": {"type": "array", "items": {"type": "string"}}
114
+ },
115
+ "required": ["count", "input_types"]
116
+ }
117
+ )
118
+ print(json.dumps(response, indent=2))
119
+
120
+ # Example 2: Count inputs in login page
121
+ print("\nExample 2: Count inputs in login page")
122
+ response = agent.prompt(
123
+ "How many input tags are in this page "+ login_page,
124
+ response_structure={
125
+ "type": "object",
126
+ "properties": {
127
+ "count": {"type": "integer"},
128
+ "input_types": {"type": "array", "items": {"type": "string"}}
129
+ },
130
+ "required": ["count", "input_types"]
131
+ }
132
+ )
133
+ print(json.dumps(response, indent=2))
@@ -1,4 +0,0 @@
1
- from .agent import Agent
2
-
3
- __version__ = "0.1.2"
4
- __all__ = ["Agent"]