gemini-agent-framework 0.1.14__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.14 → gemini_agent_framework-0.2.1}/PKG-INFO +1 -1
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/pyproject.toml +1 -1
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/src/gemini_agent/__init__.py +1 -1
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/src/gemini_agent/agent.py +70 -39
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.flake8 +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/ci.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/docs.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/python-publish.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/tests.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.gitignore +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CHANGELOG.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CODE_OF_CONDUCT.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CONTRIBUTING.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/LICENSE +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/README.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/api_reference.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/architecture.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/best_practices.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/index.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/installation.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/tutorials.md +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/mkdocs.yml +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/payload_variable_0.json +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/requirements.txt +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/__init__.py +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/test_agent.py +0 -0
- {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/test_class_methods.py +0 -0
- {gemini_agent_framework-0.1.14 → 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"
|
@@ -241,10 +241,7 @@ class Agent:
|
|
241
241
|
)
|
242
242
|
|
243
243
|
return """
|
244
|
-
|
245
|
-
Available tools:
|
246
|
-
{tools_list}
|
247
|
-
|
244
|
+
|
248
245
|
Available variables:
|
249
246
|
{variables_list}
|
250
247
|
|
@@ -302,15 +299,37 @@ class Agent:
|
|
302
299
|
result[key] = value
|
303
300
|
return result
|
304
301
|
|
305
|
-
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]:
|
306
303
|
"""Makes a call to the Gemini API."""
|
307
304
|
response = requests.post(
|
308
305
|
f"{self.base_url}:generateContent?key={self.api_key}",
|
309
306
|
headers=self.headers,
|
310
307
|
json=payload,
|
311
308
|
)
|
312
|
-
response.
|
313
|
-
|
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)
|
314
333
|
|
315
334
|
def prompt(
|
316
335
|
self,
|
@@ -318,6 +337,7 @@ class Agent:
|
|
318
337
|
system_prompt: Optional[str] = None,
|
319
338
|
response_structure: Optional[Dict[str, Any]] = None,
|
320
339
|
conversation_history: Optional[List[Dict[str, Any]]] = None,
|
340
|
+
debug_scope: Optional[str] = [],
|
321
341
|
) -> Any:
|
322
342
|
"""
|
323
343
|
Sends a prompt to the Gemini model and processes the response.
|
@@ -333,17 +353,13 @@ class Agent:
|
|
333
353
|
"""
|
334
354
|
self._intermediate_results = {}
|
335
355
|
|
336
|
-
if not system_prompt:
|
337
|
-
system_prompt = self._get_system_prompt()
|
338
|
-
else:
|
339
|
-
system_prompt = self._get_system_prompt() + system_prompt
|
340
356
|
|
341
357
|
current_contents = conversation_history if conversation_history else []
|
342
358
|
|
343
359
|
# Add system instruction to payload
|
344
360
|
payload: Dict[str, Any] = {
|
345
361
|
"system_instruction": {
|
346
|
-
"parts": [{"text": system_prompt}]
|
362
|
+
"parts": [{"text": system_prompt if system_prompt else ""},{"text": self._get_system_prompt()}]
|
347
363
|
},
|
348
364
|
"contents": current_contents
|
349
365
|
}
|
@@ -373,13 +389,16 @@ class Agent:
|
|
373
389
|
}
|
374
390
|
final_mime_type = "application/json"
|
375
391
|
final_response_schema = response_structure
|
376
|
-
|
392
|
+
count = 0
|
377
393
|
while True:
|
378
|
-
|
379
|
-
|
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)
|
380
398
|
if "error" in response_data:
|
381
|
-
|
399
|
+
self._log_text(
|
382
400
|
f"API call failed: {response_data['error'].get('message', 'Unknown API error')}"
|
401
|
+
, debug_scope
|
383
402
|
)
|
384
403
|
return response_data
|
385
404
|
|
@@ -390,24 +409,26 @@ class Agent:
|
|
390
409
|
error_msg = f"Request blocked by API. Reason: {block_reason}."
|
391
410
|
if safety_ratings:
|
392
411
|
error_msg += f" Details: {json.dumps(safety_ratings)}"
|
393
|
-
|
412
|
+
|
413
|
+
self._log_text(error_msg, debug_scope)
|
394
414
|
return {"error": {"message": error_msg, "details": feedback}}
|
395
|
-
|
415
|
+
|
396
416
|
try:
|
397
417
|
candidate = response_data["candidates"][0]
|
398
418
|
content = candidate["content"]
|
399
419
|
|
400
420
|
for part in content["parts"]:
|
401
|
-
|
421
|
+
|
402
422
|
|
403
423
|
if "functionCall" in part:
|
424
|
+
payload["contents"].append({"role": "model", "parts": [part]})
|
404
425
|
fc = part["functionCall"]
|
405
426
|
tool_name = fc["name"]
|
406
427
|
args = fc.get("args", {})
|
407
428
|
|
408
429
|
if tool_name not in self._tool_functions:
|
409
430
|
error_msg = f"Model attempted to call unknown function '{tool_name}'."
|
410
|
-
|
431
|
+
self._log_text(f"Error: {error_msg}", debug_scope)
|
411
432
|
error_response_part = {
|
412
433
|
"functionResponse": {
|
413
434
|
"name": tool_name,
|
@@ -421,7 +442,7 @@ class Agent:
|
|
421
442
|
|
422
443
|
try:
|
423
444
|
tool_function = self._tool_functions[tool_name]
|
424
|
-
|
445
|
+
self._log_text(f"--- Calling Function: {tool_name}({args}) ---", debug_scope)
|
425
446
|
|
426
447
|
# Substitute both stored variables and intermediate results
|
427
448
|
args = self._substitute_variables(args)
|
@@ -434,7 +455,7 @@ class Agent:
|
|
434
455
|
# Call the function directly - it's already bound if it's a method
|
435
456
|
function_result = tool_function(**args)
|
436
457
|
|
437
|
-
|
458
|
+
self._log_text(f"--- Function Result: {function_result} ---", debug_scope)
|
438
459
|
|
439
460
|
result_key = f"result_{len(self._intermediate_results)}"
|
440
461
|
self._intermediate_results[result_key] = function_result
|
@@ -471,7 +492,7 @@ class Agent:
|
|
471
492
|
)
|
472
493
|
|
473
494
|
except Exception as e:
|
474
|
-
|
495
|
+
self._log_text(f"Error executing function {tool_name}: {e}", debug_scope)
|
475
496
|
error_msg = f"Error during execution of tool '{tool_name}': {e}"
|
476
497
|
error_response_part = {
|
477
498
|
"functionResponse": {
|
@@ -496,8 +517,9 @@ class Agent:
|
|
496
517
|
):
|
497
518
|
return structured_output
|
498
519
|
except json.JSONDecodeError as e:
|
499
|
-
|
500
|
-
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
|
501
523
|
)
|
502
524
|
|
503
525
|
elif apply_structure_later:
|
@@ -505,14 +527,15 @@ class Agent:
|
|
505
527
|
"functionCall" in p
|
506
528
|
for p in content["parts"][content["parts"].index(part) + 1 :]
|
507
529
|
):
|
508
|
-
|
530
|
+
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
531
|
+
# Include the full conversation history in the formatting payload
|
509
532
|
formatting_payload = {
|
510
|
-
"contents": [
|
533
|
+
"contents": payload["contents"] + [
|
511
534
|
{
|
512
535
|
"role": "user",
|
513
536
|
"parts": [
|
514
537
|
{
|
515
|
-
"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}"
|
516
539
|
}
|
517
540
|
],
|
518
541
|
}
|
@@ -522,11 +545,14 @@ class Agent:
|
|
522
545
|
"response_schema": response_structure,
|
523
546
|
},
|
524
547
|
}
|
525
|
-
|
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)
|
526
551
|
|
527
552
|
if "error" in structured_response_data:
|
528
|
-
|
529
|
-
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
|
530
556
|
)
|
531
557
|
return final_text
|
532
558
|
|
@@ -537,8 +563,9 @@ class Agent:
|
|
537
563
|
structured_output = json.loads(structured_text)
|
538
564
|
return structured_output
|
539
565
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
540
|
-
|
541
|
-
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
|
542
569
|
)
|
543
570
|
return final_text
|
544
571
|
|
@@ -547,7 +574,7 @@ class Agent:
|
|
547
574
|
for p in content["parts"][content["parts"].index(part) + 1 :]
|
548
575
|
):
|
549
576
|
if response_structure and not apply_structure_later:
|
550
|
-
|
577
|
+
self._log_text("--- Attempting final structuring call ---", debug_scope)
|
551
578
|
formatting_payload = {
|
552
579
|
"contents": [
|
553
580
|
{
|
@@ -564,11 +591,14 @@ class Agent:
|
|
564
591
|
"response_schema": response_structure,
|
565
592
|
},
|
566
593
|
}
|
567
|
-
|
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)
|
568
597
|
|
569
598
|
if "error" in structured_response_data:
|
570
|
-
|
599
|
+
self._log_text(
|
571
600
|
f"Structuring call failed: {structured_response_data['error']}. Returning intermediate text."
|
601
|
+
, debug_scope
|
572
602
|
)
|
573
603
|
return final_text
|
574
604
|
|
@@ -579,15 +609,16 @@ class Agent:
|
|
579
609
|
structured_output = json.loads(structured_text)
|
580
610
|
return structured_output
|
581
611
|
except (KeyError, IndexError, json.JSONDecodeError) as e:
|
582
|
-
|
583
|
-
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
|
584
615
|
)
|
585
616
|
return final_text
|
586
617
|
return final_text
|
587
618
|
continue
|
588
619
|
|
589
620
|
except (KeyError, IndexError) as e:
|
590
|
-
|
621
|
+
self._log_text(f"Error parsing API response structure: {e}. Response: {response_data}", debug_scope)
|
591
622
|
return {
|
592
623
|
"error": {
|
593
624
|
"message": f"Error parsing API response: {e}",
|
File without changes
|
File without changes
|
{gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml
RENAMED
File without changes
|
File without changes
|
{gemini_agent_framework-0.1.14 → 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
|