gemini-agent-framework 0.1.15__tar.gz → 0.2.1__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.15 → gemini_agent_framework-0.2.1}/PKG-INFO +1 -1
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/pyproject.toml +1 -1
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/src/gemini_agent/__init__.py +1 -1
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/src/gemini_agent/agent.py +68 -31
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.flake8 +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/ci.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/docs.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/python-publish.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/tests.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.gitignore +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CHANGELOG.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CODE_OF_CONDUCT.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CONTRIBUTING.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/LICENSE +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/README.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/api_reference.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/architecture.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/best_practices.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/index.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/installation.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/tutorials.md +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/mkdocs.yml +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/payload_variable_0.json +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/requirements.txt +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/__init__.py +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/test_agent.py +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/test_class_methods.py +0 -0
- {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/test_variables.py +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.2.1
|
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
|
@@ -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.2.1"
|
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"
|
@@ -299,15 +299,37 @@ class Agent:
|
|
299
299
|
result[key] = value
|
300
300
|
return result
|
301
301
|
|
302
|
-
def _call_gemini_api(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
302
|
+
def _call_gemini_api(self, payload: Dict[str, Any], debug_scope: Optional[str] = None) -> Dict[str, Any]:
|
303
303
|
"""Makes a call to the Gemini API."""
|
304
304
|
response = requests.post(
|
305
305
|
f"{self.base_url}:generateContent?key={self.api_key}",
|
306
306
|
headers=self.headers,
|
307
307
|
json=payload,
|
308
308
|
)
|
309
|
-
response.
|
310
|
-
|
309
|
+
response_data = response.json()
|
310
|
+
self._log_text(response_data, debug_scope)
|
311
|
+
|
312
|
+
if not response.ok:
|
313
|
+
error_details = response_data.get('error', {})
|
314
|
+
error_message = f"Gemini API Error: {error_details.get('message', 'Unknown error')}"
|
315
|
+
if 'details' in error_details:
|
316
|
+
error_message += f"\nDetails: {error_details['details']}"
|
317
|
+
raise requests.exceptions.HTTPError(error_message, response=response)
|
318
|
+
|
319
|
+
return response_data
|
320
|
+
|
321
|
+
def _log_json(self, json_data: Dict[str, Any], file_name: str, debug_scope: Optional[str] = None) -> None:
|
322
|
+
"""Logs the JSON data to a file."""
|
323
|
+
print("in log json")
|
324
|
+
if "json" not in debug_scope:
|
325
|
+
return
|
326
|
+
with open(file_name, "w") as f:
|
327
|
+
json.dump(json_data, f)
|
328
|
+
def _log_text(self, text: str, debug_scope: Optional[str] = None) -> None:
|
329
|
+
"""Logs the text to a file."""
|
330
|
+
if "text" not in debug_scope:
|
331
|
+
return
|
332
|
+
print(text)
|
311
333
|
|
312
334
|
def prompt(
|
313
335
|
self,
|
@@ -315,6 +337,7 @@ class Agent:
|
|
315
337
|
system_prompt: Optional[str] = None,
|
316
338
|
response_structure: Optional[Dict[str, Any]] = None,
|
317
339
|
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
340
|
+
debug_scope: Optional[str] = [],
|
318
341
|
) -> Any:
|
319
342
|
"""
|
320
343
|
Sends a prompt to the Gemini model and processes the response.
|
@@ -331,7 +354,6 @@ class Agent:
|
|
331
354
|
self._intermediate_results = {}
|
332
355
|
|
333
356
|
|
334
|
-
|
335
357
|
current_contents = conversation_history if conversation_history else []
|
336
358
|
|
337
359
|
# Add system instruction to payload
|
@@ -367,13 +389,16 @@ class Agent:
|
|
367
389
|
}
|
368
390
|
final_mime_type = "application/json"
|
369
391
|
final_response_schema = response_structure
|
370
|
-
|
392
|
+
count = 0
|
371
393
|
while True:
|
372
|
-
|
373
|
-
|
394
|
+
self._log_json(payload, f"payload_{count}.json", debug_scope)
|
395
|
+
count += 1
|
396
|
+
response_data = self._call_gemini_api(payload, debug_scope)
|
397
|
+
print("response data " , response_data)
|
374
398
|
if "error" in response_data:
|
375
|
-
|
399
|
+
self._log_text(
|
376
400
|
f"API call failed: {response_data['error'].get('message', 'Unknown API error')}"
|
401
|
+
, debug_scope
|
377
402
|
)
|
378
403
|
return response_data
|
379
404
|
|
@@ -384,24 +409,26 @@ class Agent:
|
|
384
409
|
error_msg = f"Request blocked by API. Reason: {block_reason}."
|
385
410
|
if safety_ratings:
|
386
411
|
error_msg += f" Details: {json.dumps(safety_ratings)}"
|
387
|
-
|
412
|
+
|
413
|
+
self._log_text(error_msg, debug_scope)
|
388
414
|
return {"error": {"message": error_msg, "details": feedback}}
|
389
|
-
|
415
|
+
|
390
416
|
try:
|
391
417
|
candidate = response_data["candidates"][0]
|
392
418
|
content = candidate["content"]
|
393
419
|
|
394
420
|
for part in content["parts"]:
|
395
|
-
|
421
|
+
|
396
422
|
|
397
423
|
if "functionCall" in part:
|
424
|
+
payload["contents"].append({"role": "model", "parts": [part]})
|
398
425
|
fc = part["functionCall"]
|
399
426
|
tool_name = fc["name"]
|
400
427
|
args = fc.get("args", {})
|
401
428
|
|
402
429
|
if tool_name not in self._tool_functions:
|
403
430
|
error_msg = f"Model attempted to call unknown function '{tool_name}'."
|
404
|
-
|
431
|
+
self._log_text(f"Error: {error_msg}", debug_scope)
|
405
432
|
error_response_part = {
|
406
433
|
"functionResponse": {
|
407
434
|
"name": tool_name,
|
@@ -415,7 +442,7 @@ class Agent:
|
|
415
442
|
|
416
443
|
try:
|
417
444
|
tool_function = self._tool_functions[tool_name]
|
418
|
-
|
445
|
+
self._log_text(f"--- Calling Function: {tool_name}({args}) ---", debug_scope)
|
419
446
|
|
420
447
|
# Substitute both stored variables and intermediate results
|
421
448
|
args = self._substitute_variables(args)
|
@@ -428,7 +455,7 @@ class Agent:
|
|
428
455
|
# Call the function directly - it's already bound if it's a method
|
429
456
|
function_result = tool_function(**args)
|
430
457
|
|
431
|
-
|
458
|
+
self._log_text(f"--- Function Result: {function_result} ---", debug_scope)
|
432
459
|
|
433
460
|
result_key = f"result_{len(self._intermediate_results)}"
|
434
461
|
self._intermediate_results[result_key] = function_result
|
@@ -465,7 +492,7 @@ class Agent:
|
|
465
492
|
)
|
466
493
|
|
467
494
|
except Exception as e:
|
468
|
-
|
495
|
+
self._log_text(f"Error executing function {tool_name}: {e}", debug_scope)
|
469
496
|
error_msg = f"Error during execution of tool '{tool_name}': {e}"
|
470
497
|
error_response_part = {
|
471
498
|
"functionResponse": {
|
@@ -490,8 +517,9 @@ class Agent:
|
|
490
517
|
):
|
491
518
|
return structured_output
|
492
519
|
except json.JSONDecodeError as e:
|
493
|
-
|
494
|
-
f"Warning: Failed to parse initially structured output: {e}. Continuing with raw text."
|
520
|
+
self._log_text(
|
521
|
+
f"Warning: Failed to parse initially structured output: {e}. Continuing with raw text.",
|
522
|
+
debug_scope
|
495
523
|
)
|
496
524
|
|
497
525
|
elif apply_structure_later:
|
@@ -499,14 +527,15 @@ class Agent:
|
|
499
527
|
"functionCall" in p
|
500
528
|
for p in content["parts"][content["parts"].index(part) + 1 :]
|
501
529
|
):
|
502
|
-
|
530
|
+
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
531
|
+
# Include the full conversation history in the formatting payload
|
503
532
|
formatting_payload = {
|
504
|
-
"contents": [
|
533
|
+
"contents": payload["contents"] + [
|
505
534
|
{
|
506
535
|
"role": "user",
|
507
536
|
"parts": [
|
508
537
|
{
|
509
|
-
"text": f"
|
538
|
+
"text": f"Based on our conversation above, please format the following information according to the requested JSON structure:\n\n{final_text}"
|
510
539
|
}
|
511
540
|
],
|
512
541
|
}
|
@@ -516,11 +545,14 @@ class Agent:
|
|
516
545
|
"response_schema": response_structure,
|
517
546
|
},
|
518
547
|
}
|
519
|
-
|
548
|
+
self._log_json(formatting_payload, f"formatting_payload_{count}.json", debug_scope)
|
549
|
+
count += 1
|
550
|
+
structured_response_data = self._call_gemini_api(formatting_payload, debug_scope)
|
520
551
|
|
521
552
|
if "error" in structured_response_data:
|
522
|
-
|
523
|
-
f"Structuring call failed: {structured_response_data['error']}. Returning intermediate text."
|
553
|
+
self._log_text(
|
554
|
+
f"Structuring call failed: {structured_response_data['error']}. Returning intermediate text.",
|
555
|
+
debug_scope
|
524
556
|
)
|
525
557
|
return final_text
|
526
558
|
|
@@ -531,8 +563,9 @@ class Agent:
|
|
531
563
|
structured_output = json.loads(structured_text)
|
532
564
|
return structured_output
|
533
565
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
534
|
-
|
535
|
-
f"Warning: Failed to parse structured output after formatting call: {e}. Returning intermediate text."
|
566
|
+
self._log_text(
|
567
|
+
f"Warning: Failed to parse structured output after formatting call: {e}. Returning intermediate text.",
|
568
|
+
debug_scope
|
536
569
|
)
|
537
570
|
return final_text
|
538
571
|
|
@@ -541,7 +574,7 @@ class Agent:
|
|
541
574
|
for p in content["parts"][content["parts"].index(part) + 1 :]
|
542
575
|
):
|
543
576
|
if response_structure and not apply_structure_later:
|
544
|
-
|
577
|
+
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
545
578
|
formatting_payload = {
|
546
579
|
"contents": [
|
547
580
|
{
|
@@ -558,11 +591,14 @@ class Agent:
|
|
558
591
|
"response_schema": response_structure,
|
559
592
|
},
|
560
593
|
}
|
561
|
-
|
594
|
+
self._log_json(formatting_payload, f"formatting_payload_{count}.json", debug_scope)
|
595
|
+
count += 1
|
596
|
+
structured_response_data = self._call_gemini_api(formatting_payload, debug_scope)
|
562
597
|
|
563
598
|
if "error" in structured_response_data:
|
564
|
-
|
599
|
+
self._log_text(
|
565
600
|
f"Structuring call failed: {structured_response_data['error']}. Returning intermediate text."
|
601
|
+
, debug_scope
|
566
602
|
)
|
567
603
|
return final_text
|
568
604
|
|
@@ -573,15 +609,16 @@ class Agent:
|
|
573
609
|
structured_output = json.loads(structured_text)
|
574
610
|
return structured_output
|
575
611
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
576
|
-
|
577
|
-
f"Warning: Failed to parse structured output after formatting call: {e}. Returning intermediate text."
|
612
|
+
self._log_text(
|
613
|
+
f"Warning: Failed to parse structured output after formatting call: {e}. Returning intermediate text.",
|
614
|
+
debug_scope
|
578
615
|
)
|
579
616
|
return final_text
|
580
617
|
return final_text
|
581
618
|
continue
|
582
619
|
|
583
620
|
except (KeyError, IndexError) as e:
|
584
|
-
|
621
|
+
self._log_text(f"Error parsing API response structure: {e}. Response: {response_data}", debug_scope)
|
585
622
|
return {
|
586
623
|
"error": {
|
587
624
|
"message": f"Error parsing API response: {e}",
|
File without changes
|
File without changes
|
{gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml
RENAMED
File without changes
|
File without changes
|
{gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|