gemini-agent-framework 0.1.0__tar.gz → 0.1.2__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.
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/.gitignore +1 -1
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/PKG-INFO +1 -1
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/pyproject.toml +1 -1
- gemini_agent_framework-0.1.2/src/gemini_agent/__init__.py +4 -0
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/src/gemini_agent/agent.py +25 -2
- gemini_agent_framework-0.1.2/tests/test_agent.py +66 -0
- gemini_agent_framework-0.1.2/tests/test_class_methods.py +67 -0
- gemini_agent_framework-0.1.0/src/gemini_agent/__init__.py +0 -4
- gemini_agent_framework-0.1.0/tests/test_agent.py +0 -48
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/README.md +0 -0
- {gemini_agent_framework-0.1.0 → gemini_agent_framework-0.1.2}/requirements.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gemini-agent-framework
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
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.
|
7
|
+
version = "0.1.2"
|
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"
|
@@ -31,6 +31,7 @@ class Agent:
|
|
31
31
|
Agent._tools_registry[func.__name__]['description'] = desc
|
32
32
|
Agent._tools_registry[func.__name__]['signature'] = inspect.signature(func)
|
33
33
|
Agent._tools_registry[func.__name__]['function_ref'] = func
|
34
|
+
Agent._tools_registry[func.__name__]['is_method'] = inspect.ismethod(func)
|
34
35
|
@wraps(func)
|
35
36
|
def wrapper(*args, **kwargs):
|
36
37
|
return func(*args, **kwargs)
|
@@ -48,6 +49,7 @@ class Agent:
|
|
48
49
|
Agent._tools_registry[func.__name__]['signature'] = inspect.signature(func)
|
49
50
|
if 'function_ref' not in Agent._tools_registry[func.__name__]:
|
50
51
|
Agent._tools_registry[func.__name__]['function_ref'] = func
|
52
|
+
Agent._tools_registry[func.__name__]['is_method'] = inspect.ismethod(func)
|
51
53
|
@wraps(func)
|
52
54
|
def wrapper(*args, **kwargs):
|
53
55
|
return func(*args, **kwargs)
|
@@ -60,7 +62,7 @@ class Agent:
|
|
60
62
|
|
61
63
|
Args:
|
62
64
|
api_key: Your Google Generative AI API key.
|
63
|
-
tools: A list of Python functions decorated as tools.
|
65
|
+
tools: A list of Python functions or class methods decorated as tools.
|
64
66
|
model_name: The name of the Gemini model to use.
|
65
67
|
"""
|
66
68
|
if not api_key:
|
@@ -72,6 +74,7 @@ class Agent:
|
|
72
74
|
|
73
75
|
self._registered_tools_json: List[Dict[str, Any]] = [] # Store JSON representation
|
74
76
|
self._tool_functions: Dict[str, Callable] = {} # Map name to actual function
|
77
|
+
self._tool_instances: Dict[str, Any] = {} # Store instances for class methods
|
75
78
|
self._intermediate_results: Dict[str, Any] = {} # Store intermediate results
|
76
79
|
|
77
80
|
if tools:
|
@@ -90,6 +93,12 @@ class Agent:
|
|
90
93
|
print(f"Warning: Function '{tool_name}' is missing @Agent.description. Skipping.")
|
91
94
|
continue
|
92
95
|
|
96
|
+
# Store the bound method directly if it's a class method
|
97
|
+
if inspect.ismethod(func):
|
98
|
+
self._tool_functions[tool_name] = func
|
99
|
+
else:
|
100
|
+
self._tool_functions[tool_name] = metadata['function_ref']
|
101
|
+
|
93
102
|
# Build the parameters schema JSON
|
94
103
|
gemini_params_schema = {
|
95
104
|
"type": "OBJECT",
|
@@ -102,6 +111,9 @@ class Agent:
|
|
102
111
|
if not params_def and signature:
|
103
112
|
params_def = {}
|
104
113
|
for name, param in signature.parameters.items():
|
114
|
+
# Skip 'self' parameter for class methods
|
115
|
+
if name == 'self' and inspect.ismethod(func):
|
116
|
+
continue
|
105
117
|
py_type = param.annotation if param.annotation != inspect.Parameter.empty else str
|
106
118
|
params_def[name] = {'type': py_type, 'description': f'Parameter {name}'}
|
107
119
|
|
@@ -125,7 +137,6 @@ class Agent:
|
|
125
137
|
del declaration_json["parameters"]
|
126
138
|
|
127
139
|
self._registered_tools_json.append(declaration_json)
|
128
|
-
self._tool_functions[tool_name] = metadata['function_ref']
|
129
140
|
|
130
141
|
def _get_system_prompt(self) -> str:
|
131
142
|
"""Returns a system prompt that guides the model in breaking down complex operations."""
|
@@ -193,6 +204,8 @@ class Agent:
|
|
193
204
|
|
194
205
|
if not system_prompt:
|
195
206
|
system_prompt = self._get_system_prompt()
|
207
|
+
else:
|
208
|
+
system_prompt = self._get_system_prompt() + system_prompt
|
196
209
|
|
197
210
|
current_contents = conversation_history if conversation_history else []
|
198
211
|
if system_prompt and not current_contents:
|
@@ -212,6 +225,14 @@ class Agent:
|
|
212
225
|
|
213
226
|
if response_structure and not self._registered_tools_json:
|
214
227
|
apply_structure_later = False
|
228
|
+
# If response_structure is a string type, make it more flexible
|
229
|
+
if response_structure.get("type") == "string":
|
230
|
+
response_structure = {
|
231
|
+
"type": ["string", "object"],
|
232
|
+
"properties": {
|
233
|
+
"value": {"type": "string"}
|
234
|
+
}
|
235
|
+
}
|
215
236
|
payload["generationConfig"] = {
|
216
237
|
"response_mime_type": "application/json",
|
217
238
|
"response_schema": response_structure
|
@@ -270,7 +291,9 @@ class Agent:
|
|
270
291
|
if result_key in self._intermediate_results:
|
271
292
|
args[key] = self._intermediate_results[result_key]
|
272
293
|
|
294
|
+
# Call the function directly - it's already bound if it's a method
|
273
295
|
function_result = tool_function(**args)
|
296
|
+
|
274
297
|
print(f"--- Function Result: {function_result} ---")
|
275
298
|
|
276
299
|
result_key = f"result_{len(self._intermediate_results)}"
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import os
|
2
|
+
from dotenv import load_dotenv
|
3
|
+
from gemini_agent import Agent
|
4
|
+
|
5
|
+
load_dotenv()
|
6
|
+
|
7
|
+
def test_basic_operations():
|
8
|
+
# Define some basic math operations
|
9
|
+
@Agent.description("Multiplies two numbers.")
|
10
|
+
@Agent.parameters({
|
11
|
+
'a': {'type': int, 'description': 'The first number'},
|
12
|
+
'b': {'type': int, 'description': 'The second number'}
|
13
|
+
})
|
14
|
+
def multiply(a: int, b: int) -> int:
|
15
|
+
return a * b
|
16
|
+
|
17
|
+
@Agent.description("Adds two numbers.")
|
18
|
+
@Agent.parameters({
|
19
|
+
'a': {'type': int, 'description': 'The first number'},
|
20
|
+
'b': {'type': int, 'description': 'The second number'}
|
21
|
+
})
|
22
|
+
def add(a: int, b: int) -> int:
|
23
|
+
return a + b
|
24
|
+
|
25
|
+
# Create an agent with the math tools
|
26
|
+
agent = Agent(
|
27
|
+
api_key=os.getenv("GEMINI_API_KEY"),
|
28
|
+
tools=[multiply, add]
|
29
|
+
)
|
30
|
+
|
31
|
+
# Test a simple multiplication
|
32
|
+
response = agent.prompt("Multiply 3 and 7")
|
33
|
+
print(f"Multiplication result: {response}") # Should be 21
|
34
|
+
|
35
|
+
# Use the agent
|
36
|
+
response = agent.prompt(user_prompt="multiply 3 and 7 then add 5 to the result" ,
|
37
|
+
system_prompt="You are a helpful assistant give your response always with ❤️ at the start of the line. in your response you should mention the function you used." ,
|
38
|
+
response_structure=
|
39
|
+
{
|
40
|
+
"type": "object",
|
41
|
+
"properties": {
|
42
|
+
"used_functions": {
|
43
|
+
"type": "array",
|
44
|
+
"items": {
|
45
|
+
"type": "object",
|
46
|
+
"properties": {
|
47
|
+
"function_name": {"type": "string"},
|
48
|
+
"parameters": {
|
49
|
+
"type": "object",
|
50
|
+
"properties": {
|
51
|
+
"a": {"type": "integer"},
|
52
|
+
"b": {"type": "integer"}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
},
|
58
|
+
"answer": {"type": "string"}
|
59
|
+
|
60
|
+
}
|
61
|
+
}
|
62
|
+
)
|
63
|
+
print(response) # Should output 21
|
64
|
+
|
65
|
+
if __name__ == "__main__":
|
66
|
+
test_basic_operations()
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import os
|
2
|
+
from dotenv import load_dotenv
|
3
|
+
from gemini_agent import Agent
|
4
|
+
|
5
|
+
load_dotenv()
|
6
|
+
|
7
|
+
class Calculator:
|
8
|
+
def __init__(self):
|
9
|
+
self.memory = 0
|
10
|
+
|
11
|
+
@Agent.description("Multiplies a number by the stored memory value.")
|
12
|
+
@Agent.parameters({
|
13
|
+
'number': {'type': int, 'description': 'The number to multiply with memory'}
|
14
|
+
})
|
15
|
+
def multiply_with_memory(self, number: int) -> int:
|
16
|
+
result = self.memory * number
|
17
|
+
self.memory = result
|
18
|
+
return result
|
19
|
+
|
20
|
+
@Agent.description("Adds a number to the stored memory value.")
|
21
|
+
@Agent.parameters({
|
22
|
+
'number': {'type': int, 'description': 'The number to add to memory'}
|
23
|
+
})
|
24
|
+
def add_to_memory(self, number: int) -> int:
|
25
|
+
result = self.memory + number
|
26
|
+
self.memory = result
|
27
|
+
return result
|
28
|
+
|
29
|
+
def test_class_methods():
|
30
|
+
# Create a calculator instance
|
31
|
+
calculator = Calculator()
|
32
|
+
|
33
|
+
# Create an agent with the calculator methods
|
34
|
+
agent = Agent(
|
35
|
+
api_key=os.getenv("GEMINI_API_KEY"),
|
36
|
+
tools=[calculator.multiply_with_memory, calculator.add_to_memory]
|
37
|
+
)
|
38
|
+
|
39
|
+
# Test using class methods
|
40
|
+
response = agent.prompt(
|
41
|
+
"Multiply 5 with memory (starting at 0), then add 10 to the result",
|
42
|
+
response_structure={
|
43
|
+
"type": "object",
|
44
|
+
"properties": {
|
45
|
+
"used_functions": {
|
46
|
+
"type": "array",
|
47
|
+
"items": {
|
48
|
+
"type": "object",
|
49
|
+
"properties": {
|
50
|
+
"function_name": {"type": "string"},
|
51
|
+
"parameters": {
|
52
|
+
"type": "object",
|
53
|
+
"properties": {
|
54
|
+
"number": {"type": "integer"}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
},
|
60
|
+
"answer": {"type": "string"}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
)
|
64
|
+
print(response)
|
65
|
+
|
66
|
+
if __name__ == "__main__":
|
67
|
+
test_class_methods()
|
@@ -1,48 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
from dotenv import load_dotenv
|
3
|
-
from src.gemini_agent import Agent
|
4
|
-
|
5
|
-
load_dotenv()
|
6
|
-
|
7
|
-
def test_basic_operations():
|
8
|
-
# Define some basic math operations
|
9
|
-
@Agent.description("Multiplies two numbers.")
|
10
|
-
@Agent.parameters({
|
11
|
-
'a': {'type': int, 'description': 'The first number'},
|
12
|
-
'b': {'type': int, 'description': 'The second number'}
|
13
|
-
})
|
14
|
-
def multiply(a: int, b: int) -> int:
|
15
|
-
return a * b
|
16
|
-
|
17
|
-
@Agent.description("Adds two numbers.")
|
18
|
-
@Agent.parameters({
|
19
|
-
'a': {'type': int, 'description': 'The first number'},
|
20
|
-
'b': {'type': int, 'description': 'The second number'}
|
21
|
-
})
|
22
|
-
def add(a: int, b: int) -> int:
|
23
|
-
return a + b
|
24
|
-
|
25
|
-
# Create an agent with the math tools
|
26
|
-
agent = Agent(
|
27
|
-
api_key=os.getenv("GEMINI_API_KEY"),
|
28
|
-
tools=[multiply, add]
|
29
|
-
)
|
30
|
-
|
31
|
-
# Test a simple multiplication
|
32
|
-
response = agent.prompt("Multiply 3 and 7")
|
33
|
-
print(f"Multiplication result: {response}") # Should be 21
|
34
|
-
|
35
|
-
# Test a complex operation
|
36
|
-
response = agent.prompt(
|
37
|
-
"Multiply 3 and 7, then add 4 to the result",
|
38
|
-
response_structure={
|
39
|
-
"type": "object",
|
40
|
-
"properties": {
|
41
|
-
"result": {"type": "number"}
|
42
|
-
}
|
43
|
-
}
|
44
|
-
)
|
45
|
-
print(f"Complex operation result: {response}") # Should be {"result": 25}
|
46
|
-
|
47
|
-
if __name__ == "__main__":
|
48
|
-
test_basic_operations()
|
File without changes
|
File without changes
|