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.
Files changed (29) hide show
  1. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/PKG-INFO +1 -1
  2. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/pyproject.toml +1 -1
  3. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/src/gemini_agent/__init__.py +1 -1
  4. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/src/gemini_agent/agent.py +70 -39
  5. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.flake8 +0 -0
  6. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/ci.yml +0 -0
  7. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/deploy-docs.yml +0 -0
  8. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/docs.yml +0 -0
  9. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/python-publish.yml +0 -0
  10. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.github/workflows/tests.yml +0 -0
  11. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/.gitignore +0 -0
  12. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CHANGELOG.md +0 -0
  13. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CODE_OF_CONDUCT.md +0 -0
  14. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/CONTRIBUTING.md +0 -0
  15. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/LICENSE +0 -0
  16. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/README.md +0 -0
  17. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/api_reference.md +0 -0
  18. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/architecture.md +0 -0
  19. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/best_practices.md +0 -0
  20. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/index.md +0 -0
  21. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/installation.md +0 -0
  22. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/docs/tutorials.md +0 -0
  23. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/mkdocs.yml +0 -0
  24. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/payload_variable_0.json +0 -0
  25. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/requirements.txt +0 -0
  26. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/__init__.py +0 -0
  27. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/test_agent.py +0 -0
  28. {gemini_agent_framework-0.1.14 → gemini_agent_framework-0.2.1}/tests/test_class_methods.py +0 -0
  29. {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.14
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.14"
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.14"
3
+ __version__ = "0.2.1"
4
4
  __all__ = ["Agent"]
@@ -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.raise_for_status()
313
- 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)
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
- 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)
380
398
  if "error" in response_data:
381
- print(
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
- print(error_msg)
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
- payload["contents"].append({"role": "model", "parts": [part]})
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
- print(f"Error: {error_msg}")
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
- print(f"--- Calling Function: {tool_name}({args}) ---")
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
- print(f"--- Function Result: {function_result} ---")
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
- print(f"Error executing function {tool_name}: {e}")
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
- print(
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
- 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
509
532
  formatting_payload = {
510
- "contents": [
533
+ "contents": payload["contents"] + [
511
534
  {
512
535
  "role": "user",
513
536
  "parts": [
514
537
  {
515
- "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}"
516
539
  }
517
540
  ],
518
541
  }
@@ -522,11 +545,14 @@ class Agent:
522
545
  "response_schema": response_structure,
523
546
  },
524
547
  }
525
- 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)
526
551
 
527
552
  if "error" in structured_response_data:
528
- print(
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
- print(
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
- print("--- Attempting final structuring call ---")
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
- 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)
568
597
 
569
598
  if "error" in structured_response_data:
570
- print(
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
- print(
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
- 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)
591
622
  return {
592
623
  "error": {
593
624
  "message": f"Error parsing API response: {e}",