Conversational Agent Gemini
Conversational agent gemini example.
Conversational AI Agent using Google Gemini.
Run it
python examples/ai/conversational_agent_gemini.py
"""
Conversational AI Agent using Google Gemini.
This example uses Google's Gemini API which excels at:
- Long-form conversations with extended context
- Complex reasoning and analysis
- Following detailed instructions
Prerequisites:
1. Get a Gemini API key: https://aistudio.google.com/apikey
2. Set the API key as a secret:
flux secrets set GEMINI_API_KEY "your-api-key"
Usage:
# Start a new conversation
flux workflow run conversational_agent_gemini '{"message": "Why is the sky blue?"}'
# Resume the conversation
flux workflow resume conversational_agent_gemini <execution_id> '{"message": "Why does the sky turn red and orange during sunset?"}'
# Specify the model explicitly (uses Gemini 2.5 Flash by default)
flux workflow run conversational_agent_gemini '{"message": "What color would the sky be on Mars?", "model": "gemini-2.5-pro"}'
"""
from __future__ import annotations
from typing import Any
from google import genai
from google.genai import types
from flux import ExecutionContext, task, workflow
from flux.tasks import pause
@task.with_options(
secret_requests=["GEMINI_API_KEY"],
retry_max_attempts=3,
retry_delay=1,
retry_backoff=2,
timeout=60,
)
async def call_gemini_api(
messages: list[dict[str, str]],
system_prompt: str,
model: str,
max_tokens: int,
secrets: dict[str, Any] | None = None,
) -> tuple[str, int, int]:
"""
Call Gemini API to generate a response using the official SDK.
Args:
messages: Conversation history
system_prompt: System instructions for the model
model: The Gemini model to use
max_tokens: Maximum tokens in the response
secrets: Dictionary containing GEMINI_API_KEY
Returns:
Tuple of (assistant_response, input_tokens, output_tokens)
"""
if not secrets or "GEMINI_API_KEY" not in secrets:
raise ValueError(
"GEMINI_API_KEY not found. Set it using: flux secrets set GEMINI_API_KEY 'your-key'",
)
try:
client = genai.Client(api_key=secrets["GEMINI_API_KEY"])
contents = [
types.Content(
role="model" if msg["role"] == "assistant" else "user",
parts=[types.Part(text=msg["content"])],
)
for msg in messages
]
config = types.GenerateContentConfig(
system_instruction=system_prompt,
max_output_tokens=max_tokens,
)
response = await client.aio.models.generate_content(
model=model,
contents=contents,
config=config,
)
assistant_message = response.text
input_tokens = response.usage_metadata.prompt_token_count
output_tokens = response.usage_metadata.candidates_token_count
return assistant_message, input_tokens, output_tokens
except Exception as e:
raise RuntimeError(f"Failed to call Gemini API: {str(e)}") from e
@task
async def conversation_turn(
messages: list[dict[str, str]],
user_message: str,
system_prompt: str,
model: str,
max_tokens: int,
) -> tuple[list[dict[str, str]], str, int, int]:
"""
Process one turn of the conversation.
Args:
messages: Current conversation history
user_message: The user's message
system_prompt: System prompt for the LLM
model: Gemini model to use
max_tokens: Maximum tokens per response
Returns:
Tuple of (updated messages, assistant response, input tokens, output tokens)
"""
messages.append({"role": "user", "content": user_message})
assistant_response, input_tokens, output_tokens = await call_gemini_api(
messages=messages,
system_prompt=system_prompt,
model=model,
max_tokens=max_tokens,
)
messages.append({"role": "assistant", "content": assistant_response})
return messages, assistant_response, input_tokens, output_tokens
@workflow
async def conversational_agent_gemini(ctx: ExecutionContext[dict[str, Any]]):
"""
A conversational AI agent using Google's Gemini models.
Initial Input format:
{
"message": "User's message",
"system_prompt": "Optional system prompt",
"model": "gemini-2.5-flash", # Latest Gemini model
"max_tokens": 1024, # Optional: max tokens per response
"max_turns": 10 # Optional: maximum conversation turns
}
Resume Input format:
{
"message": "User's next message"
}
"""
initial_input = ctx.input or {}
system_prompt = initial_input.get(
"system_prompt",
"You are a helpful AI assistant. Be concise and informative.",
)
model = initial_input.get("model", "gemini-2.5-flash")
max_tokens = initial_input.get("max_tokens", 1024)
max_turns = initial_input.get("max_turns", 10)
messages: list[dict[str, str]] = []
total_input_tokens = 0
total_output_tokens = 0
first_message = initial_input.get("message", "")
if not first_message:
return {"error": "No message provided in initial input", "execution_id": ctx.execution_id}
messages, _, input_tokens, output_tokens = await conversation_turn(
messages,
first_message,
system_prompt,
model,
max_tokens,
)
total_input_tokens += input_tokens
total_output_tokens += output_tokens
for turn in range(1, max_turns):
resume_input = await pause(f"waiting_for_user_input_turn_{turn}")
next_message = resume_input.get("message", "") if resume_input else ""
if not next_message:
return {
"error": "No message provided in resume input",
"turn_count": len(messages) // 2,
"execution_id": ctx.execution_id,
"conversation_history": messages,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"total_tokens": total_input_tokens + total_output_tokens,
}
messages, _, input_tokens, output_tokens = await conversation_turn(
messages,
next_message,
system_prompt,
model,
max_tokens,
)
total_input_tokens += input_tokens
total_output_tokens += output_tokens
return {
"status": "conversation_ended",
"reason": f"Maximum turns ({max_turns}) reached",
"conversation_history": messages,
"turn_count": len(messages) // 2,
"total_input_tokens": total_input_tokens,
"total_output_tokens": total_output_tokens,
"total_tokens": total_input_tokens + total_output_tokens,
"model": model,
"execution_id": ctx.execution_id,
}
if __name__ == "__main__": # pragma: no cover
import json
import os
from flux.secret_managers import SecretManager
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
print("Error: GEMINI_API_KEY not found in environment.")
print("Set it using: export GEMINI_API_KEY='your-key'")
exit(1)
secret_manager = SecretManager.current()
secret_manager.save("GEMINI_API_KEY", api_key)
initial_input = {
"message": "Why is the sky blue?",
"model": "gemini-2.5-flash",
"max_turns": 3,
}
try:
result = conversational_agent_gemini.run(initial_input)
if result.has_failed:
raise Exception(f"Workflow failed: {result.output}")
result = conversational_agent_gemini.resume(
result.execution_id,
{"message": "Why does the sky turn red and orange during sunset?"},
)
if result.has_failed:
raise Exception(f"Workflow failed: {result.output}")
result = conversational_agent_gemini.resume(
result.execution_id,
{"message": "What color would the sky be on Mars?"},
)
if result.has_failed:
raise Exception(f"Workflow failed: {result.output}")
print(
f"Total Tokens: {result.output.get('total_tokens', 0)} "
f"(in: {result.output.get('total_input_tokens', 0)}, "
f"out: {result.output.get('total_output_tokens', 0)})",
)
print(json.dumps(result.output.get("conversation_history", []), indent=2))
except Exception as e:
print(f"Error: {e}")
Last verified against Flux 0.56.0.