Documentation
¶
Overview ¶
Package gemini wraps an ADK Gemini model.LLM with the behavior mast needs for unattended operation: server-side built-in tool injection (Google Search / URL Context / Code Execution), Vertex explicit context-cache stamping, empty-response detection + retry, and cache-eviction recovery.
Unlike its core-agent ancestor, this package does NOT construct the base LLM and carries no provider registry or config coupling — mast builds the base model itself (see internal/compose) and hands it to Wrap along with an Options struct describing the backend it fronts.
Index ¶
Constants ¶
const AuthorGoogleSearch = "gemini/google_search"
AuthorGoogleSearch is the synthetic event Author used for both "model issued a search query" and "model grounded on this web source" projected events. Stable across releases so eventlog consumers can filter on it.
Variables ¶
var ErrEmptyResponse = errors.New("gemini: model returned no usable content with no finish reason and no error — likely a silent safety filter, streaming truncation, or transient Vertex fault; retrying often succeeds")
ErrEmptyResponse is surfaced by the Gemini adapter when the model returns no usable content AND no explicit finish reason AND no error — the "silent hang" pattern #220 documents. The error text names the likely upstream causes so operators reading the daemon log get an actionable next step rather than a mystery.
Callers (typically the agent loop) may treat this as retryable — empty responses from Vertex are usually transient (safety filter race, streaming truncation, provisional-throughput mismatch). A second attempt often succeeds; a persistent pattern signals a deeper Vertex-side issue worth escalating.
Functions ¶
func GroundingProjection ¶
GroundingProjection wraps a session.Service so that every event carrying Gemini server-side built-in evidence (today: GoogleSearch grounding) is followed by one or more synthetic events surfacing that evidence under a stable Author namespace:
- "gemini/google_search" — one event per web search query the model issued, then one per grounded web source (title + URI)
Synthetic events share the parent event's InvocationID and Branch so they participate in eventlog queries (WithAuthor, WithBranchPrefix, WithSessionTree). Their Content.Role is left empty so ADK's content processor skips them when assembling the LLM's conversation history — they're for audit + display, not conversation context.
Wiring: wrap the session.Service before handing it to the agent, e.g.
svc = gemini.GroundingProjection(svc) agent.New(model, agent.WithSessionService(svc))
URLContext evidence is not projected today: ADK's gemini wrapper drops URLContextMetadata at conversion (only GroundingMetadata is lifted onto model.LLMResponse). Capturing it would require intercepting raw genai responses below the ADK boundary; deferred until a consumer needs it.
func Wrap ¶
Wrap returns base wrapped with mast's Gemini behavior layer per opts. The returned LLM is stateless and safe for concurrent use.
Wrap always wraps — even with a zero Options the result carries the empty-response detection + retry-once safety nets, which are backend-independent. Callers that need the raw base model back (e.g. a subtask path that must pass EXACTLY its own tool set) can duck-type for the WithoutBuiltins() method — see (*builtinsLLM).WithoutBuiltins.
Types ¶
type BuiltinTools ¶
type BuiltinTools struct {
GoogleSearch bool // Public web search grounding (default baseline: on)
URLContext bool // Fetch + ground on URLs the model decides to visit (default baseline: on)
CodeExecution bool // Sandboxed Python execution on Google's servers (default baseline: off)
}
BuiltinTools toggles Gemini's server-side built-in tools surfaced by mast. Each enabled flag becomes its own *genai.Tool entry injected into the request's Config.Tools alongside any user-defined function declarations.
Recommended baseline (DefaultBuiltinTools):
- GoogleSearch + URLContext are on (universally useful, no setup)
- CodeExecution is off (useful but a real action surface — opt in when you've decided sandboxed Python on Google's servers is acceptable for your security and cost posture)
To customize, set the struct explicitly:
llm := gemini.Wrap(base, gemini.Options{
BuiltinTools: gemini.BuiltinTools{
GoogleSearch: true, // URL context + CodeExecution off
},
})
Other genai built-ins (FileSearch, GoogleMaps, ComputerUse, EnterpriseWebSearch, GoogleSearchRetrieval, Retrieval) aren't surfaced here. They require upstream setup (a corpus, a Maps API key, a hosted environment) or are Vertex-only — flipping them on without configuring the upstream resource yields an API error, not a working tool. Add them when an actual consumer needs them.
func DefaultBuiltinTools ¶
func DefaultBuiltinTools() BuiltinTools
DefaultBuiltinTools returns the recommended on-by-default baseline (GoogleSearch + URLContext on, CodeExecution off). The Options zero value carries NO built-ins — pass this helper explicitly:
llm := gemini.Wrap(base, gemini.Options{BuiltinTools: gemini.DefaultBuiltinTools()})
type ContextCacheInitFn ¶
type ContextCacheInitFn func(ctx context.Context, systemInstruction *genai.Content, tools []*genai.Tool)
ContextCacheInitFn is called on the first GenerateContent request with the fully-assembled system instruction + tools ADK is about to send. Implementations typically snapshot these into a Vertex explicit-cache Create call (async — must not block the request).
type ContextCacheInvalidateFn ¶
type ContextCacheInvalidateFn func(reason string)
ContextCacheInvalidateFn is called when a GenerateContent response carries a NOT_FOUND for the stamped cache reference — the signal that Vertex has reaped our cache server-side (TTL elapsed while the daemon held a valid-looking Manager handle). Implementations flip their manager back to a pre-Init state so:
- The follow-up retry (issued by GenerateContent itself) runs uncached.
- The next turn's Init call fires a fresh Create instead of the daemon staying uncached for the rest of its lifetime.
The reason string is opaque; wired into the operator-facing log line so grep-triage can distinguish TTL eviction from other 404 shapes as the deployment matures.
type ContextCacheNameFn ¶
ContextCacheNameFn returns the currently-resolved cache name to stamp onto GenerateContentConfig.CachedContent, or "" if no cache is available yet (async Init still in flight, failed, or explicitly disabled). Empty return = request runs uncached, which is always safe — the caller degrades gracefully.
type Options ¶
type Options struct {
// BuiltinTools toggles Gemini's server-side built-in tools. Each
// enabled flag becomes its own *genai.Tool entry appended to the
// request's Config.Tools alongside any user-defined function
// declarations. Zero value = no built-ins; pass
// DefaultBuiltinTools() for the standard GoogleSearch + URLContext
// baseline.
BuiltinTools BuiltinTools
// IncludeServerSideToolInvocations must be set when the wrapper
// fronts the direct Gemini API (genai.BackendGeminiAPI) and
// built-ins ride alongside function tools — Gemini 3+ rejects the
// combination without the flag. Leave false on Vertex AI, which
// rejects the parameter outright ("includeServerSideToolInvocations
// parameter is not supported in Gemini Enterprise Agent Platform
// (previously known as Vertex AI)") but permits the combination
// unconditionally instead.
IncludeServerSideToolInvocations bool
// TolerateEmptyChunks swallows ADK's per-chunk "empty response"
// errors on streaming requests. Vertex's streaming search-grounding
// path intermittently emits chunks with empty Candidates[]
// (heartbeat-like, carrying only UsageMetadata/ResponseID); ADK can
// surface these as fatal errors that poison the stream before the
// grounded chunks arrive. Set on Vertex; leave false on the direct
// Gemini API to preserve real "no content" failure signaling.
TolerateEmptyChunks bool
// ContextCacheInit + ContextCacheName wire Vertex explicit context
// caching (#221). Init captures the fully-assembled system
// instruction + tools on the first uncached call (stamp side);
// Name returns the resolved cache handle to stamp onto
// GenerateContentConfig.CachedContent, or "" to run uncached
// (strip side degrades gracefully). Both nil = no caching. Only
// meaningful on the Vertex backend — the direct Gemini API rejects
// the cache-reference parameter on some model families.
ContextCacheInit ContextCacheInitFn
ContextCacheName ContextCacheNameFn
// ContextCacheInvalidate is the eviction-recovery hook — called
// when GenerateContent detects that Vertex has reaped the cache
// server-side (NOT_FOUND on the stamped reference). See
// ContextCacheInvalidateFn. Optional: without it, this-turn retry
// still fires but the manager isn't reset, so later turns keep
// attempting the dead handle until an external reset.
ContextCacheInvalidate ContextCacheInvalidateFn
}
Options configures the wrapper returned by Wrap. The zero value is valid: no built-ins injected, no cache hooks, no backend-specific flags — the wrapper still contributes the empty-response detection + retry-once safety net (#220 / #78).