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.
Files changed (29) hide show
  1. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/PKG-INFO +1 -1
  2. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/pyproject.toml +1 -1
  3. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/src/gemini_agent/__init__.py +1 -1
  4. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/src/gemini_agent/agent.py +68 -31
  5. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.flake8 +0 -0
  6. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/ci.yml +0 -0
  7. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml +0 -0
  8. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/docs.yml +0 -0
  9. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/python-publish.yml +0 -0
  10. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.github/workflows/tests.yml +0 -0
  11. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/.gitignore +0 -0
  12. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CHANGELOG.md +0 -0
  13. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CODE_OF_CONDUCT.md +0 -0
  14. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/CONTRIBUTING.md +0 -0
  15. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/LICENSE +0 -0
  16. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/README.md +0 -0
  17. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/api_reference.md +0 -0
  18. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/architecture.md +0 -0
  19. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/best_practices.md +0 -0
  20. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/index.md +0 -0
  21. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/installation.md +0 -0
  22. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/docs/tutorials.md +0 -0
  23. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/mkdocs.yml +0 -0
  24. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/payload_variable_0.json +0 -0
  25. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/requirements.txt +0 -0
  26. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/__init__.py +0 -0
  27. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/test_agent.py +0 -0
  28. {gemini_agent_framework-0.1.15 → gemini_agent_framework-0.2.1}/tests/test_class_methods.py +0 -0
  29. {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.15
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.15"
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"
@@ -1,4 +1,4 @@
1
1
  from .agent import Agent
2
2
 
3
- __version__ = "0.1.15"
3
+ __version__ = "0.2.1"
4
4
  __all__ = ["Agent"]
@@ -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.raise_for_status()
310
- return response.json()
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
- response_data = self._call_gemini_api(payload)
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
- print(
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
- print(error_msg)
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
- payload["contents"].append({"role": "model", "parts": [part]})
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
- print(f"Error: {error_msg}")
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
- print(f"--- Calling Function: {tool_name}({args}) ---")
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
- print(f"--- Function Result: {function_result} ---")
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
- print(f"Error executing function {tool_name}: {e}")
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
- print(
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
- print("--- Attempting final structuring call ---")
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"Please format the following information according to the requested JSON structure:\n\n{final_text}"
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
- structured_response_data = self._call_gemini_api(formatting_payload)
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
- print(
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
- print(
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
- print("--- Attempting final structuring call ---")
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
- structured_response_data = self._call_gemini_api(formatting_payload)
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
- print(
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
- print(
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
- print(f"Error parsing API response structure: {e}. Response: {response_data}")
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}",