chore: import upstream snapshot with attribution
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
"""Google ADK agents used by the Promptfoo integration example."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from google.adk.agents import Agent, SequentialAgent
|
||||
from google.adk.apps import App
|
||||
from google.adk.plugins import BasePlugin
|
||||
from google.adk.tools import ToolContext
|
||||
from google.genai import types
|
||||
|
||||
APP_NAME = "promptfoo_adk_demo"
|
||||
|
||||
WEATHER_REPORTS = {
|
||||
"london": "London is cloudy with light drizzle and 14 C temperatures.",
|
||||
"new york": "New York is sunny with a light breeze and 22 C temperatures.",
|
||||
"tokyo": "Tokyo is clear with mild humidity and 24 C temperatures.",
|
||||
}
|
||||
|
||||
|
||||
def _normalize_city(city: str) -> str:
|
||||
return city.strip().casefold()
|
||||
|
||||
|
||||
def before_agent_callback(callback_context) -> None:
|
||||
"""Track how often ADK enters the main conversational agent."""
|
||||
|
||||
callback_context.state["callback_invocations"] = (
|
||||
int(callback_context.state.get("callback_invocations", 0)) + 1
|
||||
)
|
||||
|
||||
|
||||
def get_weather(city: str, tool_context: ToolContext) -> dict[str, Any]:
|
||||
"""Return sample weather data and remember the most recent city."""
|
||||
|
||||
normalized_city = _normalize_city(city)
|
||||
report = WEATHER_REPORTS.get(
|
||||
normalized_city,
|
||||
f"No sample weather is stored for {city}.",
|
||||
)
|
||||
tool_context.state["last_city"] = city
|
||||
return {
|
||||
"city": city,
|
||||
"status": "success" if normalized_city in WEATHER_REPORTS else "not_found",
|
||||
"report": report,
|
||||
}
|
||||
|
||||
|
||||
async def save_trip_note(
|
||||
city: str,
|
||||
summary: str,
|
||||
tool_context: ToolContext,
|
||||
) -> dict[str, Any]:
|
||||
"""Save a short trip note as an ADK artifact."""
|
||||
|
||||
filename = f"{_normalize_city(city).replace(' ', '-')}-trip-note.md"
|
||||
artifact = types.Part.from_bytes(
|
||||
data=f"# Trip note for {city}\n\n{summary}\n".encode("utf-8"),
|
||||
mime_type="text/markdown",
|
||||
)
|
||||
version = await tool_context.save_artifact(filename=filename, artifact=artifact)
|
||||
tool_context.state["last_saved_artifact"] = filename
|
||||
return {
|
||||
"city": city,
|
||||
"filename": filename,
|
||||
"version": version,
|
||||
}
|
||||
|
||||
|
||||
class AuditPlugin(BasePlugin):
|
||||
"""Record runner lifecycle callbacks so the provider can expose them."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(name="audit_plugin")
|
||||
self.events: list[str] = []
|
||||
|
||||
async def before_run_callback(self, *, invocation_context) -> None:
|
||||
self.events.append(f"before_run:{invocation_context.session.id}")
|
||||
|
||||
async def after_run_callback(self, *, invocation_context) -> None:
|
||||
self.events.append(f"after_run:{invocation_context.session.id}")
|
||||
|
||||
|
||||
def build_conversational_app(model: str) -> tuple[App, AuditPlugin]:
|
||||
"""Build the conversational ADK app used by the main eval."""
|
||||
|
||||
audit_plugin = AuditPlugin()
|
||||
root_agent = Agent(
|
||||
name="weather_agent",
|
||||
model=model,
|
||||
description="Answers weather questions and saves trip notes.",
|
||||
instruction=(
|
||||
"You are a concise travel weather assistant. "
|
||||
"When the user asks about weather, call get_weather. "
|
||||
"When the user asks to save a note, call save_trip_note using the "
|
||||
"city already discussed and a brief summary of the weather. "
|
||||
"When the user asks what city was discussed earlier, answer from the "
|
||||
"conversation and current session state."
|
||||
),
|
||||
tools=[get_weather, save_trip_note],
|
||||
before_agent_callback=before_agent_callback,
|
||||
)
|
||||
return (
|
||||
App(name=APP_NAME, root_agent=root_agent, plugins=[audit_plugin]),
|
||||
audit_plugin,
|
||||
)
|
||||
|
||||
|
||||
def build_workflow_app(model: str) -> App:
|
||||
"""Build a small SequentialAgent workflow for the workflow eval."""
|
||||
|
||||
weather_lookup_agent = Agent(
|
||||
name="weather_lookup_agent",
|
||||
model=model,
|
||||
description="Looks up weather for the requested city.",
|
||||
instruction=(
|
||||
"Call get_weather for the city in the user's request, then return a "
|
||||
"single-sentence weather summary."
|
||||
),
|
||||
tools=[get_weather],
|
||||
output_key="weather_snapshot",
|
||||
)
|
||||
briefing_agent = Agent(
|
||||
name="briefing_agent",
|
||||
model=model,
|
||||
description="Turns the weather snapshot into a compact travel brief.",
|
||||
instruction=(
|
||||
"Use the weather snapshot from state to write a one-sentence trip "
|
||||
"brief that includes the city name and a packing suggestion."
|
||||
),
|
||||
)
|
||||
workflow = SequentialAgent(
|
||||
name="trip_planning_workflow",
|
||||
description="Looks up weather, then writes a travel brief.",
|
||||
sub_agents=[weather_lookup_agent, briefing_agent],
|
||||
)
|
||||
return App(name=APP_NAME, root_agent=workflow)
|
||||
Reference in New Issue
Block a user