generated from VectorInstitute/aieng-template-implementation
-
Notifications
You must be signed in to change notification settings - Fork 0
Report Generation: Switching from OpenAI SDK to Google ADK and removing OpenAI dependencies #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lotif
wants to merge
6
commits into
main
Choose a base branch
from
marcelo/adk
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
424688e
Switching from openai sdk to google adk and removing openai dependencies
lotif 2de0341
Merge branch 'main' into marcelo/adk
lotif bcc03c9
Merge branch 'main' into marcelo/adk
lotif 5a4a475
reverting changes on notebook, changing only gemini key
lotif d785a29
Merge branch 'main' into marcelo/adk
amrit110 56e8521
Merge branch 'main' into marcelo/adk
amrit110 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,20 +13,29 @@ | |
| >>> ) | ||
| """ | ||
|
|
||
| import logging | ||
| from enum import Enum | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| import agents | ||
| from aieng.agent_evals.async_client_manager import AsyncClientManager | ||
| from aieng.agent_evals.langfuse import setup_langfuse_tracer | ||
| from aieng.agent_evals.report_generation.file_writer import ReportFileWriter | ||
| from google.adk.agents import Agent | ||
| from google.adk.events.event import Event | ||
| from pydantic import BaseModel | ||
|
|
||
|
|
||
| logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s") | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def get_report_generation_agent( | ||
| instructions: str, | ||
| sqlite_db_path: Path, | ||
| reports_output_path: Path, | ||
| langfuse_project_name: str | None, | ||
| ) -> agents.Agent: | ||
| ) -> Agent: | ||
| """ | ||
| Define the report generation agent. | ||
|
|
||
|
|
@@ -54,29 +63,153 @@ def get_report_generation_agent( | |
| client_manager = AsyncClientManager.get_instance() | ||
| report_file_writer = ReportFileWriter(reports_output_path) | ||
|
|
||
| # Define an agent using the OpenAI Agent SDK | ||
| return agents.Agent( | ||
| name="Report Generation Agent", # Agent name for logging and debugging purposes | ||
| instructions=instructions, # System instructions for the agent | ||
| # Tools available to the agent | ||
| # We wrap the `execute_sql_query` and `write_report_to_file` methods | ||
| # with `function_tool`, which will construct the tool definition JSON | ||
| # schema by extracting the necessary information from the method | ||
| # signature and docstring. | ||
| # Define an agent using Google ADK | ||
| return Agent( | ||
| name="ReportGenerationAgent", | ||
| model=client_manager.configs.default_worker_model, | ||
| instruction=instructions, | ||
| tools=[ | ||
| agents.function_tool( | ||
| client_manager.sqlite_connection(sqlite_db_path).execute, | ||
| name_override="execute_sql_query", | ||
| description_override="Execute a SQL query against the SQLite database.", | ||
| ), | ||
| agents.function_tool( | ||
| report_file_writer.write, | ||
| name_override="write_report_to_file", | ||
| description_override="Write the report data to a downloadable XLSX file.", | ||
| ), | ||
| client_manager.sqlite_connection(sqlite_db_path).execute, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about using the shared
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm gonna do that on the next PR. |
||
| report_file_writer.write, | ||
| ], | ||
| model=agents.OpenAIChatCompletionsModel( | ||
| model=client_manager.configs.default_worker_model, | ||
| openai_client=client_manager.openai_client, | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| class EventType(Enum): | ||
| """Types of events from agents.""" | ||
|
|
||
| FINAL_RESPONSE = "final_response" | ||
| TOOL_CALL = "tool_call" | ||
| THOUGHT = "thought" | ||
| TOOL_RESPONSE = "tool_response" | ||
|
|
||
|
|
||
| class ParsedEvent(BaseModel): | ||
| """Parsed event from an agent.""" | ||
|
|
||
| type: EventType | ||
| text: str | ||
| arguments: Any | None = None | ||
|
|
||
|
|
||
| class EventParser: | ||
| """Parser for agent events.""" | ||
|
|
||
| @classmethod | ||
| def parse(cls, event: Event) -> list[ParsedEvent]: | ||
| """Parse an agent event into a list of parsed events. | ||
|
|
||
| The event can be a final response, a thought, a tool call, | ||
| or a tool response. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| event : Event | ||
| The event to parse. | ||
|
|
||
| Returns | ||
| ------- | ||
| list[ParsedEvent] | ||
| A list of parsed events. | ||
| """ | ||
| parsed_events = [] | ||
|
|
||
| if event.is_final_response(): | ||
| parsed_events.extend(cls._parse_final_response(event)) | ||
|
|
||
| elif event.content: | ||
| if event.content.role == "model": | ||
| parsed_events.extend(cls._parse_model_response(event)) | ||
|
|
||
| elif event.content.role == "user": | ||
| parsed_events.extend(cls._parse_user_response(event)) | ||
|
|
||
| else: | ||
| logger.warning(f"Unknown stream event: {event}") | ||
|
|
||
| return parsed_events | ||
|
|
||
| @classmethod | ||
| def _parse_final_response(cls, event: Event) -> list[ParsedEvent]: | ||
| if ( | ||
| not event.content | ||
| or not event.content.parts | ||
| or len(event.content.parts) == 0 | ||
| or not event.content.parts[0].text | ||
| ): | ||
| logger.warning(f"Final response's content is not valid: {event}") | ||
| return [] | ||
|
|
||
| return [ | ||
| ParsedEvent( | ||
| type=EventType.FINAL_RESPONSE, | ||
| text=event.content.parts[0].text, | ||
| ) | ||
| ] | ||
|
|
||
| @classmethod | ||
| def _parse_model_response(cls, event: Event) -> list[ParsedEvent]: | ||
| if not event.content or not event.content.parts: | ||
| logger.warning(f"Model response's content is not valid: {event}") | ||
| return [] | ||
|
|
||
| parsed_events = [] | ||
|
|
||
| for part in event.content.parts: | ||
| # Parsing tool calls and their arguments | ||
| if part.function_call: | ||
| if not part.function_call.name: | ||
| logger.warning(f"No name in function call: {part}") | ||
| continue | ||
|
|
||
| parsed_events.append( | ||
| ParsedEvent( | ||
| type=EventType.TOOL_CALL, | ||
| text=part.function_call.name, | ||
| arguments=part.function_call.args, | ||
| ) | ||
| ) | ||
|
|
||
| # Parsing the agent's thoughts | ||
| elif part.thought_signature or (part.text and not part.thought_signature): | ||
| if not part.text: | ||
| logger.warning(f"No text in part: {part}") | ||
| continue | ||
|
|
||
| parsed_events.append( | ||
| ParsedEvent( | ||
| type=EventType.THOUGHT, | ||
| text=part.text, | ||
| ) | ||
| ) | ||
|
|
||
| else: | ||
| logger.warning(f"Unknown part type: {part}") | ||
|
|
||
| return parsed_events | ||
|
|
||
| @classmethod | ||
| def _parse_user_response(cls, event: Event) -> list[ParsedEvent]: | ||
| if not event.content or not event.content.parts: | ||
| logger.warning(f"Model response's content is not valid: {event}") | ||
| return [] | ||
|
|
||
| parsed_events = [] | ||
|
|
||
| for part in event.content.parts: | ||
| if part.function_response: | ||
| if not part.function_response.name: | ||
| logger.warning(f"No name in function response: {part}") | ||
| continue | ||
|
|
||
| parsed_events.append( | ||
| ParsedEvent( | ||
| type=EventType.TOOL_RESPONSE, | ||
| text=part.function_response.name, | ||
| arguments=part.function_response.response, | ||
| ) | ||
| ) | ||
| else: | ||
| logger.warning(f"Unknown part type: {part}") | ||
|
|
||
| return parsed_events | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note to consider deprecating this in favor of
ReadOnlySqlDatabase