feat: Add Google Gemini plugin for Flyte#632
feat: Add Google Gemini plugin for Flyte#632andreahlert wants to merge 1 commit intoflyteorg:mainfrom
Conversation
Add a new plugin that integrates Google's Gemini API with Flyte, enabling Flyte tasks to be used as tools for Gemini agents. The plugin provides: - FunctionTool: wraps Flyte tasks or regular callables as Gemini function declarations with automatic JSON schema generation - function_tool: decorator/converter for creating tools from functions and Flyte tasks - Agent: configuration dataclass for Gemini agent settings - run_agent: async agent loop that handles function calling, error handling, and conversation state management Includes comprehensive test coverage (19 tests) and a sandwich-making example that demonstrates multi-tool orchestration. Signed-off-by: André Ahlert <andre@aex.partners>
9aa8a7e to
9e56006
Compare
|
|
||
| def _get_function_schema(func: typing.Callable) -> dict[str, typing.Any]: | ||
| """Extract JSON schema from a function's type hints.""" | ||
| sig = inspect.signature(func) |
There was a problem hiding this comment.
you should not need to do this, this is already done as part of the AsyncFunctionTemplate - native interface
There was a problem hiding this comment.
I checked NativeInterface before going this route. It stores Python types as Dict[str, Tuple[Type, Any]] but doesn't expose a JSON schema conversion. Gemini's FunctionDeclaration needs parameters_json_schema as a JSON schema dict, so some conversion layer is needed regardless.
This is the same approach used in the Anthropic plugin (plugins/anthropic/.../agents/_function_tools.py, lines 34-66). Also, function_tool() needs to support regular callables and @flyte.trace decorated functions too, where NativeInterface isn't available.
Happy to refactor if there's a method I'm missing that already does this conversion.
|
|
||
| tool_name = name or actual_func.__name__ | ||
| tool_description = description or (actual_func.__doc__ or f"Execute {tool_name}") | ||
| input_schema = _get_function_schema(actual_func) |
There was a problem hiding this comment.
you already have native_interface
There was a problem hiding this comment.
native_interface is only set when func is an AsyncFunctionTaskTemplate. For plain callables it's None, so we'd still need the inspect fallback. The Anthropic plugin stores native_interface the same way but generates the schema from the raw function for this reason.
One thing I could do is use native_interface.inputs when available and fall back to inspect otherwise. Would that be the direction you'd prefer?
| if self.task is not None: | ||
| if self.is_async: | ||
| return await self.task(**kwargs) | ||
| return await asyncio.to_thread(self.task, **kwargs) |
There was a problem hiding this comment.
this is not needed and dangerous. this will start non daemon threads which will block. you dont need to do it, this is all solved by flyte, it gives you an async interface. doing the to_thread is not recommended.
i think we should just call the async execute method. it takes care of the rest
There was a problem hiding this comment.
I hear you on avoiding unnecessary threads. I looked at how the SDK handles this internally, and AsyncFunctionTaskTemplate.execute() itself uses run_sync_with_loop() for sync functions, which also spins up a thread with its own event loop (src/flyte/_utils/asyncify.py).
The reason for to_thread here: for sync Flyte tasks, task(**kwargs) goes through __call__ -> controller.submit_sync() which returns a blocking Future.result(None). Without to_thread, that blocks the event loop while the agent loop needs to stay async to handle multiple tool calls.
That said, if there's a cleaner async path I should be using instead, I'm happy to switch. The Anthropic plugin uses the same to_thread pattern, so if there's a better approach we could align both.
|
I dont think this is right, i have not looked at the anthropic plugin, but this will result in bugs and instability |
Summary
This PR adds a new plugin for integrating Google's Gemini API with Flyte, following the same patterns as the existing OpenAI and Anthropic plugins.
Features
function_tooldecorator: Convert Flyte tasks to Gemini function declarations automaticallyAgentclass: Configure Gemini agents with model, instructions, and toolsrun_agentfunction: Execute agent loops that handle function calling and responsesUsage Example
Files Added
plugins/gemini/- Plugin packagepyproject.toml- Package configurationREADME.md- Documentationsrc/flyteplugins/gemini/agents/_function_tools.py- Core implementationtests/test_agents.py- Test suite (19 tests)examples/genai/gemini_agent.py- Example workflowTest Plan
Why Gemini?
Google Gemini is one of the leading LLM providers alongside OpenAI and Anthropic. Having first-class support enables users to:
This plugin mirrors the Anthropic plugin's API design, making it easy to switch between providers.