gemini-agent-framework 0.2.3__tar.gz → 0.2.5__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.2.3 → gemini_agent_framework-0.2.5}/PKG-INFO +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/api_reference.md +2 -7
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/best_practices.md +2 -6
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/tutorials.md +3 -7
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/pyproject.toml +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/src/gemini_agent/__init__.py +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/src/gemini_agent/agent.py +36 -89
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/test_agent.py +1 -19
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/test_class_methods.py +0 -21
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/test_variables.py +16 -18
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.flake8 +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/ci.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/deploy-docs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/docs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/python-publish.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/tests.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.gitignore +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/CHANGELOG.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/CODE_OF_CONDUCT.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/CONTRIBUTING.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/LICENSE +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/README.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/architecture.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/index.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/docs/installation.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/mkdocs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/payload_variable_0.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/requirements.txt +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/__init__.py +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/formatting_payload_2.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/payload_0.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/payload_1.json +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gemini-agent-framework
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.5
|
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://m7mdony.github.io/gemini-agent-framework
|
@@ -120,15 +120,10 @@ The framework automatically maps Python types to Gemini JSON schema types:
|
|
120
120
|
|
121
121
|
## Response Structure
|
122
122
|
|
123
|
-
The `
|
123
|
+
The `json_format` parameter in the `prompt` method allows you to define the expected structure with in the prompt:
|
124
124
|
|
125
125
|
```python
|
126
|
-
|
127
|
-
"field_name": {
|
128
|
-
"type": "string|number|boolean|array|object",
|
129
|
-
"description": "Optional description"
|
130
|
-
}
|
131
|
-
}
|
126
|
+
Json_format = True
|
132
127
|
```
|
133
128
|
|
134
129
|
## Error Handling
|
@@ -120,14 +120,10 @@ agent.set_variable('count', 5, 'Counter')
|
|
120
120
|
|
121
121
|
### 1. Structured Responses
|
122
122
|
|
123
|
-
Define clear response structures:
|
123
|
+
Define clear response structures within the prompt then apply them:
|
124
124
|
|
125
125
|
```python
|
126
|
-
|
127
|
-
'result': {'type': 'number', 'description': 'The calculation result'},
|
128
|
-
'steps': {'type': 'array', 'description': 'List of calculation steps'},
|
129
|
-
'explanation': {'type': 'string', 'description': 'Explanation of the calculation'}
|
130
|
-
}
|
126
|
+
json_format = True
|
131
127
|
```
|
132
128
|
|
133
129
|
### 2. Error Responses
|
@@ -136,15 +136,11 @@ def safe_divide(a: float, b: float) -> float:
|
|
136
136
|
### 2. Using Response Structures
|
137
137
|
|
138
138
|
```python
|
139
|
-
|
140
|
-
'result': {'type': 'number', 'description': 'The calculation result'},
|
141
|
-
'steps': {'type': 'array', 'description': 'List of calculation steps'},
|
142
|
-
'explanation': {'type': 'string', 'description': 'Explanation of the calculation'}
|
143
|
-
}
|
139
|
+
|
144
140
|
|
145
141
|
response = agent.prompt(
|
146
|
-
"Calculate 15 * 7 and show your work",
|
147
|
-
|
142
|
+
"""Calculate 15 * 7 and show your work respond with {"answer": number}""",
|
143
|
+
json_format=True
|
148
144
|
)
|
149
145
|
```
|
150
146
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "gemini-agent-framework"
|
7
|
-
version = "0.2.
|
7
|
+
version = "0.2.5"
|
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"
|
@@ -328,7 +328,7 @@ class Agent:
|
|
328
328
|
self,
|
329
329
|
user_prompt: str,
|
330
330
|
system_prompt: Optional[str] = None,
|
331
|
-
|
331
|
+
json_format: bool = False,
|
332
332
|
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
333
333
|
debug_scope: Optional[str] = [],
|
334
334
|
) -> Any:
|
@@ -338,15 +338,14 @@ class Agent:
|
|
338
338
|
Args:
|
339
339
|
user_prompt: The user's input prompt
|
340
340
|
system_prompt: Optional system prompt to override the default
|
341
|
-
|
341
|
+
json_format: If True, response will be formatted as JSON. Default is False (plain text)
|
342
342
|
conversation_history: Optional list of previous conversation turns
|
343
343
|
|
344
344
|
Returns:
|
345
|
-
The model's response,
|
345
|
+
The model's response, formatted as JSON if json_format is True, otherwise plain text
|
346
346
|
"""
|
347
347
|
self._intermediate_results = {}
|
348
348
|
|
349
|
-
|
350
349
|
current_contents = conversation_history if conversation_history else []
|
351
350
|
|
352
351
|
# Add system instruction to payload
|
@@ -364,24 +363,16 @@ class Agent:
|
|
364
363
|
payload["tools"] = [{"functionDeclarations": self._registered_tools_json}]
|
365
364
|
payload["toolConfig"] = {"functionCallingConfig": {"mode": "AUTO"}}
|
366
365
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
if
|
372
|
-
|
373
|
-
# If response_structure is a string type, make it more flexible
|
374
|
-
if response_structure.get("type") == "string":
|
375
|
-
response_structure = {
|
376
|
-
"type": ["string", "object"],
|
377
|
-
"properties": {"value": {"type": "string"}},
|
378
|
-
}
|
366
|
+
# Don't set JSON formatting initially if tools are available
|
367
|
+
# We'll apply it later after tool calls are completed
|
368
|
+
apply_json_format_later = json_format and bool(self._registered_tools_json)
|
369
|
+
|
370
|
+
# Set JSON formatting immediately if no tools are involved
|
371
|
+
if json_format and not self._registered_tools_json:
|
379
372
|
payload["generationConfig"] = {
|
380
|
-
"response_mime_type": "application/json"
|
381
|
-
"response_schema": response_structure,
|
373
|
+
"response_mime_type": "application/json"
|
382
374
|
}
|
383
|
-
|
384
|
-
final_response_schema = response_structure
|
375
|
+
|
385
376
|
count = 0
|
386
377
|
while True:
|
387
378
|
self._log_json(payload, f"payload_{count}.json", debug_scope)
|
@@ -410,8 +401,6 @@ class Agent:
|
|
410
401
|
content = candidate["content"]
|
411
402
|
|
412
403
|
for part in content["parts"]:
|
413
|
-
|
414
|
-
|
415
404
|
if "functionCall" in part:
|
416
405
|
payload["contents"].append({"role": "model", "parts": [part]})
|
417
406
|
fc = part["functionCall"]
|
@@ -500,41 +489,32 @@ class Agent:
|
|
500
489
|
elif "text" in part:
|
501
490
|
final_text = part["text"]
|
502
491
|
|
503
|
-
if
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
self._log_text(
|
513
|
-
f"Warning: Failed to parse initially structured output: {e}. Continuing with raw text.",
|
514
|
-
debug_scope
|
515
|
-
)
|
516
|
-
|
517
|
-
elif apply_structure_later:
|
518
|
-
if not any(
|
519
|
-
"functionCall" in p
|
520
|
-
for p in content["parts"][content["parts"].index(part) + 1 :]
|
521
|
-
):
|
522
|
-
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
523
|
-
# Include the full conversation history in the formatting payload
|
492
|
+
# Check if there are more function calls coming
|
493
|
+
has_more_function_calls = any(
|
494
|
+
"functionCall" in p
|
495
|
+
for p in content["parts"][content["parts"].index(part) + 1 :]
|
496
|
+
)
|
497
|
+
|
498
|
+
if not has_more_function_calls:
|
499
|
+
# If JSON format is requested and we have tools, make a final formatting call
|
500
|
+
if apply_json_format_later:
|
501
|
+
self._log_text("--- Making final JSON formatting call ---", debug_scope)
|
524
502
|
formatting_payload = {
|
503
|
+
"system_instruction": {
|
504
|
+
"parts": [{"text": system_prompt if system_prompt else ""},{"text": self._get_system_prompt()}]
|
505
|
+
},
|
525
506
|
"contents": payload["contents"] + [
|
526
507
|
{
|
527
508
|
"role": "user",
|
528
509
|
"parts": [
|
529
510
|
{
|
530
|
-
"text": f"Based on our conversation above, please format
|
511
|
+
"text": f"Based on our conversation above, please format your response as JSON. Here is the current response: {final_text}"
|
531
512
|
}
|
532
513
|
],
|
533
514
|
}
|
534
515
|
],
|
535
516
|
"generationConfig": {
|
536
|
-
"response_mime_type": "application/json"
|
537
|
-
"response_schema": response_structure,
|
517
|
+
"response_mime_type": "application/json"
|
538
518
|
},
|
539
519
|
}
|
540
520
|
self._log_json(formatting_payload, f"formatting_payload_{count}.json", debug_scope)
|
@@ -543,7 +523,7 @@ class Agent:
|
|
543
523
|
|
544
524
|
if "error" in structured_response_data:
|
545
525
|
self._log_text(
|
546
|
-
f"
|
526
|
+
f"JSON formatting call failed: {structured_response_data['error']}. Returning raw text.",
|
547
527
|
debug_scope
|
548
528
|
)
|
549
529
|
return final_text
|
@@ -556,57 +536,24 @@ class Agent:
|
|
556
536
|
return structured_output
|
557
537
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
558
538
|
self._log_text(
|
559
|
-
f"Warning: Failed to parse
|
539
|
+
f"Warning: Failed to parse JSON response after formatting call: {e}. Returning raw text.",
|
560
540
|
debug_scope
|
561
541
|
)
|
562
542
|
return final_text
|
563
|
-
|
564
|
-
|
565
|
-
"functionCall" in p
|
566
|
-
for p in content["parts"][content["parts"].index(part) + 1 :]
|
567
|
-
):
|
568
|
-
if response_structure and not apply_structure_later:
|
569
|
-
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
570
|
-
formatting_payload = {
|
571
|
-
"contents": [
|
572
|
-
{
|
573
|
-
"role": "user",
|
574
|
-
"parts": [
|
575
|
-
{
|
576
|
-
"text": f"Please format the following information according to the requested JSON structure:\n\n{final_text}"
|
577
|
-
}
|
578
|
-
],
|
579
|
-
}
|
580
|
-
],
|
581
|
-
"generationConfig": {
|
582
|
-
"response_mime_type": "application/json",
|
583
|
-
"response_schema": response_structure,
|
584
|
-
},
|
585
|
-
}
|
586
|
-
self._log_json(formatting_payload, f"formatting_payload_{count}.json", debug_scope)
|
587
|
-
count += 1
|
588
|
-
structured_response_data = self._call_gemini_api(formatting_payload, debug_scope)
|
589
|
-
|
590
|
-
if "error" in structured_response_data:
|
591
|
-
self._log_text(
|
592
|
-
f"Structuring call failed: {structured_response_data['error']}. Returning intermediate text."
|
593
|
-
, debug_scope
|
594
|
-
)
|
595
|
-
return final_text
|
596
|
-
|
543
|
+
elif json_format:
|
544
|
+
# Direct JSON formatting (no tools involved)
|
597
545
|
try:
|
598
|
-
|
599
|
-
"content"
|
600
|
-
]["parts"][0]["text"]
|
601
|
-
structured_output = json.loads(structured_text)
|
546
|
+
structured_output = json.loads(final_text)
|
602
547
|
return structured_output
|
603
|
-
except
|
548
|
+
except json.JSONDecodeError as e:
|
604
549
|
self._log_text(
|
605
|
-
f"Warning: Failed to parse
|
550
|
+
f"Warning: Failed to parse JSON response: {e}. Returning raw text.",
|
606
551
|
debug_scope
|
607
552
|
)
|
608
553
|
return final_text
|
609
|
-
|
554
|
+
else:
|
555
|
+
# Return plain text response
|
556
|
+
return final_text
|
610
557
|
continue
|
611
558
|
|
612
559
|
except (KeyError, IndexError) as e:
|
@@ -64,25 +64,7 @@ response = agent_prompt_with_key_rotation(
|
|
64
64
|
agent,
|
65
65
|
user_prompt="multiply 3 and 7 then add 5 to the result",
|
66
66
|
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.",
|
67
|
-
|
68
|
-
"type": "object",
|
69
|
-
"properties": {
|
70
|
-
"used_functions": {
|
71
|
-
"type": "array",
|
72
|
-
"items": {
|
73
|
-
"type": "object",
|
74
|
-
"properties": {
|
75
|
-
"function_name": {"type": "string"},
|
76
|
-
"parameters": {
|
77
|
-
"type": "object",
|
78
|
-
"properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
|
79
|
-
},
|
80
|
-
},
|
81
|
-
},
|
82
|
-
},
|
83
|
-
"answer": {"type": "string"},
|
84
|
-
},
|
85
|
-
},
|
67
|
+
|
86
68
|
)
|
87
69
|
|
88
70
|
print(response)
|
@@ -39,27 +39,6 @@ def test_class_methods():
|
|
39
39
|
# Test using class methods
|
40
40
|
response = agent.prompt(
|
41
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
42
|
)
|
64
43
|
print(response)
|
65
44
|
|
@@ -107,16 +107,14 @@ print("\nExample 1: Count inputs in home page")
|
|
107
107
|
response = agent.prompt(
|
108
108
|
|
109
109
|
user_prompt="How many input tags are in the home page?",
|
110
|
-
system_prompt="You are a tool that counts the number of input tags in an HTML page.
|
111
|
-
|
112
|
-
|
113
|
-
"
|
114
|
-
"
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
"required": ["count", "input_types"]
|
119
|
-
}
|
110
|
+
system_prompt=""""You are a tool that counts the number of input tags in an HTML page.
|
111
|
+
make the response in this format
|
112
|
+
{
|
113
|
+
"count": number,
|
114
|
+
"input_types": [input1,input2 ..... ] }
|
115
|
+
|
116
|
+
""",
|
117
|
+
json_format= True
|
120
118
|
)
|
121
119
|
print(json.dumps(response, indent=2))
|
122
120
|
|
@@ -124,13 +122,13 @@ print(json.dumps(response, indent=2))
|
|
124
122
|
print("\nExample 2: Count inputs in login page")
|
125
123
|
response = agent.prompt(
|
126
124
|
"How many input tags are in this page "+ login_page,
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
"
|
134
|
-
|
125
|
+
system_prompt="""
|
126
|
+
make the response in this format
|
127
|
+
{
|
128
|
+
"count": number,
|
129
|
+
"input_types": [input1,input2 ..... ] }
|
130
|
+
|
131
|
+
""",
|
132
|
+
json_format= True
|
135
133
|
)
|
136
134
|
print(json.dumps(response, indent=2))
|
File without changes
|
File without changes
|
{gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/deploy-docs.yml
RENAMED
File without changes
|
File without changes
|
{gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/.github/workflows/python-publish.yml
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.5}/tests/formatting_payload_2.json
RENAMED
File without changes
|
File without changes
|
File without changes
|