gemini-agent-framework 0.2.3__tar.gz → 0.2.4__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.4}/PKG-INFO +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/api_reference.md +2 -7
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/best_practices.md +2 -6
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/tutorials.md +3 -7
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/pyproject.toml +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/src/gemini_agent/__init__.py +1 -1
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/src/gemini_agent/agent.py +32 -91
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/test_agent.py +1 -19
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/test_class_methods.py +0 -21
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/test_variables.py +16 -18
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.flake8 +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.github/workflows/ci.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.github/workflows/deploy-docs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.github/workflows/docs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.github/workflows/python-publish.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.github/workflows/tests.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.gitignore +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/CHANGELOG.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/CODE_OF_CONDUCT.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/CONTRIBUTING.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/LICENSE +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/README.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/architecture.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/index.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/docs/installation.md +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/mkdocs.yml +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/payload_variable_0.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/requirements.txt +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/__init__.py +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/formatting_payload_2.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/tests/payload_0.json +0 -0
- {gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/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.4
|
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.4"
|
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,10 @@ 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 response_structure and not self._registered_tools_json:
|
372
|
-
apply_structure_later = False
|
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
|
-
}
|
379
|
-
payload["generationConfig"] = {
|
380
|
-
"response_mime_type": "application/json",
|
381
|
-
"response_schema": response_structure,
|
382
|
-
}
|
383
|
-
final_mime_type = "application/json"
|
384
|
-
final_response_schema = response_structure
|
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
|
+
|
385
370
|
count = 0
|
386
371
|
while True:
|
387
372
|
self._log_json(payload, f"payload_{count}.json", debug_scope)
|
@@ -410,8 +395,6 @@ class Agent:
|
|
410
395
|
content = candidate["content"]
|
411
396
|
|
412
397
|
for part in content["parts"]:
|
413
|
-
|
414
|
-
|
415
398
|
if "functionCall" in part:
|
416
399
|
payload["contents"].append({"role": "model", "parts": [part]})
|
417
400
|
fc = part["functionCall"]
|
@@ -500,41 +483,32 @@ class Agent:
|
|
500
483
|
elif "text" in part:
|
501
484
|
final_text = part["text"]
|
502
485
|
|
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
|
486
|
+
# Check if there are more function calls coming
|
487
|
+
has_more_function_calls = any(
|
488
|
+
"functionCall" in p
|
489
|
+
for p in content["parts"][content["parts"].index(part) + 1 :]
|
490
|
+
)
|
491
|
+
|
492
|
+
if not has_more_function_calls:
|
493
|
+
# If JSON format is requested and we have tools, make a final formatting call
|
494
|
+
if apply_json_format_later:
|
495
|
+
self._log_text("--- Making final JSON formatting call ---", debug_scope)
|
524
496
|
formatting_payload = {
|
497
|
+
"system_instruction": {
|
498
|
+
"parts": [{"text": system_prompt if system_prompt else ""},{"text": self._get_system_prompt()}]
|
499
|
+
},
|
525
500
|
"contents": payload["contents"] + [
|
526
501
|
{
|
527
502
|
"role": "user",
|
528
503
|
"parts": [
|
529
504
|
{
|
530
|
-
"text": f"Based on our conversation above, please format
|
505
|
+
"text": f"Based on our conversation above, please format your response as JSON. Here is the current response: {final_text}"
|
531
506
|
}
|
532
507
|
],
|
533
508
|
}
|
534
509
|
],
|
535
510
|
"generationConfig": {
|
536
|
-
"response_mime_type": "application/json"
|
537
|
-
"response_schema": response_structure,
|
511
|
+
"response_mime_type": "application/json"
|
538
512
|
},
|
539
513
|
}
|
540
514
|
self._log_json(formatting_payload, f"formatting_payload_{count}.json", debug_scope)
|
@@ -543,7 +517,7 @@ class Agent:
|
|
543
517
|
|
544
518
|
if "error" in structured_response_data:
|
545
519
|
self._log_text(
|
546
|
-
f"
|
520
|
+
f"JSON formatting call failed: {structured_response_data['error']}. Returning raw text.",
|
547
521
|
debug_scope
|
548
522
|
)
|
549
523
|
return final_text
|
@@ -556,57 +530,24 @@ class Agent:
|
|
556
530
|
return structured_output
|
557
531
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
558
532
|
self._log_text(
|
559
|
-
f"Warning: Failed to parse
|
533
|
+
f"Warning: Failed to parse JSON response after formatting call: {e}. Returning raw text.",
|
560
534
|
debug_scope
|
561
535
|
)
|
562
536
|
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
|
-
|
537
|
+
elif json_format:
|
538
|
+
# Direct JSON formatting (no tools involved)
|
597
539
|
try:
|
598
|
-
|
599
|
-
"content"
|
600
|
-
]["parts"][0]["text"]
|
601
|
-
structured_output = json.loads(structured_text)
|
540
|
+
structured_output = json.loads(final_text)
|
602
541
|
return structured_output
|
603
|
-
except
|
542
|
+
except json.JSONDecodeError as e:
|
604
543
|
self._log_text(
|
605
|
-
f"Warning: Failed to parse
|
544
|
+
f"Warning: Failed to parse JSON response: {e}. Returning raw text.",
|
606
545
|
debug_scope
|
607
546
|
)
|
608
547
|
return final_text
|
609
|
-
|
548
|
+
else:
|
549
|
+
# Return plain text response
|
550
|
+
return final_text
|
610
551
|
continue
|
611
552
|
|
612
553
|
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.4}/.github/workflows/deploy-docs.yml
RENAMED
File without changes
|
File without changes
|
{gemini_agent_framework-0.2.3 → gemini_agent_framework-0.2.4}/.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.4}/tests/formatting_payload_2.json
RENAMED
File without changes
|
File without changes
|
File without changes
|