GeminiRequest { contents, system_instruction, generation_config }
GeminiContent { role, parts }
GeminiPart { text?, inline_data?, function_call?, function_response? }
GeminiGenerationConfig { temperature, top_p, top_k, max_output_tokens }
GeminiResponse { candidates, usage_metadata }
GeminiCandidate { content, finish_reason }
GeminiUsageMetadata { prompt_token_count, candidates_token_count, total_token_count }
Part of #1592
Scope
Implement the basic non-streaming chat provider for Google Gemini using the
generateContentendpoint.Files to Create
crates/zeph-llm/src/gemini.rs-- GeminiProvider struct, request/response types, LlmProvider implFiles to Modify
crates/zeph-llm/src/lib.rs-- addpub mod gemini;crates/zeph-llm/src/any.rs-- addGemini(GeminiProvider)variant, delegate_provider, list_models_remote, set_status_tx, with_generation_overridescrates/zeph-core/src/config/types.rs-- addGeminitoProviderKind,GeminiConfigstruct,gemini_api_keytoResolvedSecretscrates/zeph-core/src/bootstrap/provider.rs-- addProviderKind::Geminiarm increate_provider,"gemini"arm increate_named_providercrates/zeph-core/src/instructions.rs-- addProviderKind::Geminitodetection_pathsmatchsrc/init.rs-- add Gemini option to provider selection wizardsrc/acp.rs-- add Gemini arm to ACP model switchingKey Implementation Details
?key=query param (NOT Authorization header)systemInstructionfield (separate fromcontents)User->"user",Assistant->"model"/v1beta/models/{model}:generateContentcandidates[0].content.parts[0].textfrom responseusageMetadataforlast_usage()(promptTokenCount, candidatesTokenCount)Request/Response Types
Acceptance Criteria
provider = "gemini"in config.toml works end-to-endZEPH_GEMINI_API_KEY)context_window()returns correct value per modelname()returns"gemini"supports_streaming()returnsfalse(Phase 2)supports_tool_use()returnsfalse(Phase 3)supports_embeddings()returnsfalse(Phase 5)supports_vision()returnstruedebug_request_json()mirrors actual API payload