kivi-cli 2.0.6__tar.gz → 2.0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {kivi_cli-2.0.6/src/kivi_cli.egg-info → kivi_cli-2.0.7}/PKG-INFO +1 -1
  2. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/pyproject.toml +1 -1
  3. {kivi_cli-2.0.6 → kivi_cli-2.0.7/src/kivi_cli.egg-info}/PKG-INFO +1 -1
  4. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kivi_cli.egg-info/SOURCES.txt +1 -0
  5. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/backend.py +10 -2
  6. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/index.html +37 -2
  7. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/base.py +1 -1
  8. kivi_cli-2.0.7/src/kiviai/services/providers/gemini.py +120 -0
  9. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/model_costs.py +14 -1
  10. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/opencode.py +1 -1
  11. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/registry.py +6 -0
  12. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/MANIFEST.in +0 -0
  13. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/setup.cfg +0 -0
  14. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kivi_cli.egg-info/dependency_links.txt +0 -0
  15. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kivi_cli.egg-info/entry_points.txt +0 -0
  16. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kivi_cli.egg-info/requires.txt +0 -0
  17. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kivi_cli.egg-info/top_level.txt +0 -0
  18. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/__init__.py +0 -0
  19. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/__init__.py +0 -0
  20. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/git_service.py +0 -0
  21. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/monitor.py +0 -0
  22. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/__init__.py +0 -0
  23. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/claude.py +0 -0
  24. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/copilot.py +0 -0
  25. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/inhouse.py +0 -0
  26. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/kivi.py +0 -0
  27. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/openai_agent.py +0 -0
  28. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/orchestrator_provider.py +0 -0
  29. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/providers/vllm.py +0 -0
  30. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/scheduler.py +0 -0
  31. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/__init__.py +0 -0
  32. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/__init__.py +0 -0
  33. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/agent_orchestration/__init__.py +0 -0
  34. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/agent_orchestration/tools.py +0 -0
  35. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/bash_execution/__init__.py +0 -0
  36. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/bash_execution/sessions.py +0 -0
  37. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/code_search/__init__.py +0 -0
  38. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/code_search/tools.py +0 -0
  39. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/file_operations/__init__.py +0 -0
  40. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/file_operations/tools.py +0 -0
  41. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/markdown/__init__.py +0 -0
  42. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/markdown/custom_markdownify.py +0 -0
  43. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/markdown/mrkdwn_analysis.py +0 -0
  44. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/markdown/tools.py +0 -0
  45. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/session_workflow/__init__.py +0 -0
  46. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/session_workflow/tools.py +0 -0
  47. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/__init__.py +0 -0
  48. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/_fetcher.py +0 -0
  49. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/_store.py +0 -0
  50. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/fetch.py +0 -0
  51. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/search.py +0 -0
  52. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/copilot_tools/web/store_tools.py +0 -0
  53. {kivi_cli-2.0.6 → kivi_cli-2.0.7}/src/kiviai/services/tools/tool_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kivi-cli
3
- Version: 2.0.6
3
+ Version: 2.0.7
4
4
  Summary: Kivi AI v2 Backend — Unified FastAPI gateway for AI coding agents
5
5
  Author: santhosh_bytes
6
6
  License: Proprietary
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "kivi-cli"
7
- version = "2.0.6"
7
+ version = "2.0.7"
8
8
  description = "Kivi AI v2 Backend — Unified FastAPI gateway for AI coding agents"
9
9
  requires-python = ">=3.10"
10
10
  license = {text = "Proprietary"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kivi-cli
3
- Version: 2.0.6
3
+ Version: 2.0.7
4
4
  Summary: Kivi AI v2 Backend — Unified FastAPI gateway for AI coding agents
5
5
  Author: santhosh_bytes
6
6
  License: Proprietary
@@ -17,6 +17,7 @@ src/kiviai/services/providers/__init__.py
17
17
  src/kiviai/services/providers/base.py
18
18
  src/kiviai/services/providers/claude.py
19
19
  src/kiviai/services/providers/copilot.py
20
+ src/kiviai/services/providers/gemini.py
20
21
  src/kiviai/services/providers/inhouse.py
21
22
  src/kiviai/services/providers/kivi.py
22
23
  src/kiviai/services/providers/model_costs.py
@@ -33,7 +33,7 @@ from kiviai.services.git_service import GitService
33
33
  logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
34
34
  log = logging.getLogger("kiviai")
35
35
 
36
- app = FastAPI(title="Kivi AI v2", version="2.0.6")
36
+ app = FastAPI(title="Kivi AI v2", version="2.0.7")
37
37
  app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
38
38
 
39
39
  HERE = os.path.dirname(os.path.abspath(__file__))
@@ -161,7 +161,7 @@ async def _run_task(task: dict):
161
161
  "opencode": "opencode",
162
162
  "copilot": "copilot",
163
163
  "local": "vllm",
164
-
164
+ "gemini": "gemini",
165
165
  }
166
166
 
167
167
  # Map short model names to current Claude model IDs.
@@ -189,6 +189,13 @@ async def _run_task(task: dict):
189
189
  if "vllm_model" not in extra:
190
190
  extra["vllm_model"] = ""
191
191
 
192
+ # For "gemini" agent, pass gemini model from extra
193
+ if model_name == "gemini":
194
+ extra = task.setdefault("extra", {})
195
+ if extra.get("gemini_model"):
196
+ extra["model_override"] = extra["gemini_model"]
197
+ if extra.get("gemini_api_key"):
198
+ extra["api_key"] = extra["gemini_api_key"]
192
199
 
193
200
  log.info("_run_task starting: agent=%s provider=%s prompt=%s", model_name, provider_name, task["prompt"][:60])
194
201
  try:
@@ -1254,6 +1261,7 @@ _AGENTS = [
1254
1261
  {"id": "opencode", "name": "OpenCode", "provider": "opencode", "description": "Open-source agentic coding CLI"},
1255
1262
  {"id": "copilot", "name": "Copilot", "provider": "copilot", "description": "GitHub Copilot SDK agent"},
1256
1263
  {"id": "local", "name": "Local", "provider": "vllm", "description": "Local vLLM model (Qwen 3.5-9B)"},
1264
+ {"id": "gemini", "name": "Gemini", "provider": "gemini", "description": "Google Gemini — fast streaming, great for brainstorming"},
1257
1265
  ]
1258
1266
 
1259
1267
 
@@ -3190,6 +3190,7 @@ textarea:focus-visible {
3190
3190
  <option value="claude-code">Claude Code</option>
3191
3191
  <option value="opencode">OpenCode</option>
3192
3192
  <option value="copilot">Copilot</option>
3193
+ <option value="gemini">Gemini</option>
3193
3194
  </select>
3194
3195
  <select id="ag-model"></select>
3195
3196
  <input class="ag-cwd" id="ag-cwd" placeholder="~/project" autocomplete="off" />
@@ -3227,6 +3228,7 @@ textarea:focus-visible {
3227
3228
  <option value="claude-code">Claude Code</option>
3228
3229
  <option value="opencode">OpenCode</option>
3229
3230
  <option value="copilot">Copilot</option>
3231
+ <option value="gemini">Gemini</option>
3230
3232
  </select>
3231
3233
  <div class="ctrl-sep"></div>
3232
3234
  <div class="ctrl-group">
@@ -3494,20 +3496,40 @@ textarea:focus-visible {
3494
3496
  </table>
3495
3497
  </div>
3496
3498
 
3499
+ <h3 class="docs-h3">Gemini CLI flags — supported via UI</h3>
3500
+ <div class="docs-table-wrap">
3501
+ <table class="docs-table">
3502
+ <thead><tr><th>UI Control</th><th>Equivalent CLI flag</th><th>Notes</th></tr></thead>
3503
+ <tbody>
3504
+ <tr><td>Agent dropdown → Gemini (planned)</td><td><code>gemini -p "…"</code></td><td>Provider not wired yet — see roadmap</td></tr>
3505
+ <tr><td>Model picker</td><td><code>-m gemini-2.5-pro</code></td><td>Any Gemini model string</td></tr>
3506
+ <tr><td>Mode → plan</td><td><code>--approval-mode plan</code></td><td>Read-only, no writes</td></tr>
3507
+ <tr><td>Mode → auto</td><td><code>--approval-mode auto_edit</code></td><td>Auto-approve edits, prompt for rest</td></tr>
3508
+ <tr><td>Mode → bypass</td><td><code>--approval-mode yolo</code></td><td>Auto-approve everything</td></tr>
3509
+ <tr><td>Resume session</td><td><code>-r latest</code></td><td>Gemini uses index-based resume</td></tr>
3510
+ <tr><td>CWD / extra dirs</td><td><code>--include-directories</code></td><td>Comma-separated extra workspace dirs</td></tr>
3511
+ <tr><td>Sandbox toggle (planned)</td><td><code>-s --sandbox</code></td><td>Isolated execution environment</td></tr>
3512
+ </tbody>
3513
+ </table>
3514
+ </div>
3497
3515
 
3498
3516
  <h3 class="docs-h3">Feature Roadmap — CLI parity gaps to close</h3>
3499
3517
  <div class="docs-table-wrap">
3500
3518
  <table class="docs-table">
3501
3519
  <thead><tr><th>Feature</th><th>CLI Source</th><th>Priority</th><th>Status</th></tr></thead>
3502
3520
  <tbody>
3521
+ <tr><td>Gemini provider wiring</td><td>Gemini CLI <code>-p</code> headless</td><td>High</td><td class="status-done">Done</td></tr>
3522
+ <tr><td>Session fork UI</td><td>OpenCode <code>--fork</code>, Claude <code>--fork-session</code></td><td>High</td><td class="status-done">Done</td></tr>
3503
3523
  <tr><td>Thinking blocks toggle</td><td>OpenCode <code>--thinking</code></td><td>Medium</td><td class="status-done">Done</td></tr>
3504
3524
  <tr><td>Effort level selector</td><td>Claude <code>--effort low/medium/high/xhigh/max</code></td><td>Medium</td><td class="status-done">Done</td></tr>
3505
3525
  <tr><td>Max budget USD input</td><td>Claude <code>--max-budget-usd</code></td><td>Medium</td><td class="status-done">Done</td></tr>
3506
3526
  <tr><td>Allowed/disallowed tools</td><td>Claude <code>--allowedTools / --disallowedTools</code></td><td>Medium</td><td class="status-done">Done</td></tr>
3507
3527
  <tr><td>Custom system prompt</td><td>Claude <code>--system-prompt / --append-system-prompt</code></td><td>High</td><td class="status-done">Done</td></tr>
3508
- <tr><td>MCP server config panel</td><td>Claude <code>--mcp-config</code></td><td>High</td><td class="status-todo">TODO</td></tr>
3528
+ <tr><td>MCP server config panel</td><td>Claude/Gemini <code>--mcp-config</code></td><td>High</td><td class="status-todo">TODO</td></tr>
3509
3529
  <tr><td>File attachments on prompt</td><td>OpenCode <code>-f --file</code>, Claude <code>--file</code></td><td>High</td><td class="status-done">Done</td></tr>
3510
- <tr><td>Worktree per task</td><td>Claude <code>-w --worktree</code></td><td>Medium</td><td class="status-todo">TODO</td></tr>
3530
+ <tr><td>Worktree per task</td><td>Claude/Gemini <code>-w --worktree</code></td><td>Medium</td><td class="status-todo">TODO</td></tr>
3531
+ <tr><td>Sandbox toggle</td><td>Gemini <code>-s --sandbox</code></td><td>Low</td><td class="status-todo">TODO</td></tr>
3532
+ <tr><td>Session export/import</td><td>OpenCode <code>export / import</code></td><td>Medium</td><td class="status-todo">TODO</td></tr>
3511
3533
  <tr><td>OpenCode stats panel</td><td>OpenCode <code>stats</code> (token usage/cost history)</td><td>Low</td><td class="status-todo">TODO</td></tr>
3512
3534
  <tr><td>PR auto-run (opencode pr)</td><td>OpenCode <code>pr &lt;number&gt;</code></td><td>Medium</td><td class="status-todo">TODO</td></tr>
3513
3535
  <tr><td>Output format (JSON/stream)</td><td>Claude <code>--output-format stream-json</code></td><td>Low</td><td class="status-done">Done (internal)</td></tr>
@@ -5080,6 +5102,7 @@ const AGENT_MODELS = {
5080
5102
  { v: 'anthropic/claude-sonnet-5', label: 'anthropic/claude-sonnet-5' },
5081
5103
  { v: 'anthropic/claude-opus-4-8', label: 'anthropic/claude-opus-4-8' },
5082
5104
  { v: 'openai/gpt-5.4', label: 'openai/gpt-5.4' },
5105
+ { v: 'google/gemini-2.5-pro', label: 'google/gemini-2.5-pro' },
5083
5106
  ],
5084
5107
  'copilot': [
5085
5108
  { v: 'gpt-5.4', label: 'gpt-5.4' },
@@ -5094,6 +5117,14 @@ const AGENT_MODELS = {
5094
5117
  { v: 'o3-mini', label: 'o3-mini' },
5095
5118
  { v: 'o4-mini', label: 'o4-mini' },
5096
5119
  ],
5120
+ 'gemini': [
5121
+ { v: 'gemini-2.5-pro', label: 'gemini-2.5-pro' },
5122
+ { v: 'gemini-2.5-flash', label: 'gemini-2.5-flash' },
5123
+ { v: 'gemini-2.0-flash', label: 'gemini-2.0-flash' },
5124
+ { v: 'gemini-2.0-flash-lite', label: 'gemini-2.0-flash-lite' },
5125
+ { v: 'gemini-1.5-pro', label: 'gemini-1.5-pro' },
5126
+ { v: 'gemini-1.5-flash', label: 'gemini-1.5-flash' },
5127
+ ],
5097
5128
  };
5098
5129
 
5099
5130
  function renderModelOptions(models) {
@@ -5210,6 +5241,10 @@ function buildLaunchBody({ prompt, agent, selectedModel, cwd, extras }) {
5210
5241
  body.extra.vllm_model = selectedModel || '';
5211
5242
  body.extra.vllm_key = localStorage.getItem('vllm_key') || 'dummy';
5212
5243
  }
5244
+ if (agent === 'gemini') {
5245
+ const gKey = localStorage.getItem('gemini_api_key');
5246
+ if (gKey) body.extra.api_key = gKey;
5247
+ if (selectedModel) body.extra.gemini_model = selectedModel;
5213
5248
  }
5214
5249
  return body;
5215
5250
  }
@@ -2,7 +2,7 @@
2
2
  Base provider protocol for all AI integrations.
3
3
 
4
4
  Every provider implements this interface so the system can swap
5
- between Claude, Copilot, VLLM, etc. with zero friction.
5
+ between Claude, Gemini, Copilot, VLLM, etc. with zero friction.
6
6
  """
7
7
  from __future__ import annotations
8
8
 
@@ -0,0 +1,120 @@
1
+ """Google Gemini provider — uses google-genai SDK."""
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+ import json
6
+ import os
7
+ from typing import AsyncIterator
8
+
9
+ from .base import BaseProvider, ProviderConfig, ProviderEvent, EventType
10
+
11
+
12
+ class GeminiProvider(BaseProvider):
13
+ name = "gemini"
14
+ display_name = "Google Gemini"
15
+ description = "Google's multimodal AI. Fast streaming text generation via the Gemini API. Best for quick questions, summaries, and brainstorming. Requires GEMINI_API_KEY."
16
+ supports_streaming = True
17
+ supports_tools = False
18
+ supports_sessions = False
19
+ available_models = [
20
+ "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash",
21
+ "gemini-2.0-flash-lite", "gemini-1.5-pro", "gemini-1.5-flash",
22
+ ]
23
+
24
+ def __init__(self):
25
+ self._stop = False
26
+
27
+ async def run(self, prompt: str, config: ProviderConfig, history=None) -> AsyncIterator[ProviderEvent]:
28
+ self._stop = False
29
+
30
+ api_key = config.api_key or os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY", "")
31
+ model = config.model or "gemini-2.5-flash"
32
+
33
+ if not api_key:
34
+ yield ProviderEvent(type=EventType.ERROR, content="GEMINI_API_KEY not set")
35
+ return
36
+
37
+ try:
38
+ from google import genai
39
+ from google.genai import types
40
+
41
+ client = genai.Client(api_key=api_key)
42
+
43
+ contents = []
44
+ if history:
45
+ for h in history:
46
+ if h.get("role") in ("user", "assistant") and not h.get("metadata"):
47
+ role = "user" if h["role"] == "user" else "model"
48
+ contents.append(types.Content(role=role, parts=[types.Part(text=h["content"])]))
49
+ contents.append(types.Content(role="user", parts=[types.Part(text=prompt)]))
50
+
51
+ response = await asyncio.to_thread(
52
+ lambda: client.models.generate_content_stream(
53
+ model=model,
54
+ contents=contents,
55
+ config=types.GenerateContentConfig(
56
+ temperature=0.7,
57
+ max_output_tokens=4096,
58
+ ),
59
+ )
60
+ )
61
+
62
+ text_buf = ""
63
+ total_input_tokens = 0
64
+ total_output_tokens = 0
65
+ for chunk in response:
66
+ if self._stop:
67
+ yield ProviderEvent(type=EventType.TEXT, content="⏹ *stopped*")
68
+ yield ProviderEvent(type=EventType.DONE)
69
+ return
70
+
71
+ if chunk.text:
72
+ text_buf += chunk.text
73
+ yield ProviderEvent(type=EventType.TEXT, content=chunk.text)
74
+
75
+ # Capture usage metadata (available in the final chunk or via usage_metadata)
76
+ if hasattr(chunk, 'usage_metadata') and chunk.usage_metadata:
77
+ um = chunk.usage_metadata
78
+ total_input_tokens += getattr(um, 'prompt_token_count', 0) or 0
79
+ total_output_tokens += getattr(um, 'candidates_token_count', 0) or 0
80
+
81
+ except ImportError:
82
+ yield ProviderEvent(
83
+ type=EventType.ERROR,
84
+ content="google-genai package required: pip install google-genai",
85
+ )
86
+ return
87
+ except Exception as e:
88
+ yield ProviderEvent(type=EventType.ERROR, content=str(e))
89
+ return
90
+
91
+ # Emit cost event with calculated cost from usage
92
+ from .model_costs import estimate_cost
93
+ usage = {
94
+ "input_tokens": total_input_tokens,
95
+ "output_tokens": total_output_tokens,
96
+ }
97
+ total_cost = estimate_cost(
98
+ model,
99
+ input_tokens=total_input_tokens,
100
+ output_tokens=total_output_tokens,
101
+ )
102
+ yield ProviderEvent(
103
+ type=EventType.COST,
104
+ metadata={
105
+ "total_cost_usd": total_cost,
106
+ "usage": usage,
107
+ },
108
+ )
109
+
110
+ yield ProviderEvent(type=EventType.DONE)
111
+
112
+ async def stop(self):
113
+ self._stop = True
114
+
115
+ async def health_check(self):
116
+ api_key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY", "")
117
+ return {
118
+ "status": "ok" if api_key else "no_api_key",
119
+ "provider": self.name,
120
+ }
@@ -51,6 +51,17 @@ COSTS: dict[str, tuple[float, float]] = {
51
51
  "o3-mini": (1.10, 4.40), # O3 Mini
52
52
  "o4-mini": (1.10, 4.40), # O4 Mini
53
53
 
54
+ # ── Google Gemini ───────────────────────────────────────────
55
+ # Model (input, output)
56
+ "gemini-3.1-pro-preview": (1.25, 10.00), # Gemini 3.1 Pro
57
+ "gemini-2.5-pro": (1.25, 10.00), # Gemini 2.5 Pro
58
+ "gemini-2.5-flash": (0.30, 2.50), # Gemini 2.5 Flash
59
+ "gemini-2.5-flash-lite": (0.08, 0.60), # Gemini 2.5 Flash Lite (free tier eligible)
60
+ "gemini-2.0-flash": (0.10, 1.00), # Gemini 2.0 Flash
61
+ "gemini-2.0-flash-lite": (0.08, 0.60), # Gemini 2.0 Flash Lite
62
+ "gemini-1.5-pro": (1.25, 5.00), # Gemini 1.5 Pro
63
+ "gemini-1.5-flash": (0.08, 0.30), # Gemini 1.5 Flash
64
+
54
65
  # ── OpenCode model aliases (full paths) ─────────────────────
55
66
  "anthropic/claude-sonnet-4-20250514": (3.00, 15.00),
56
67
  "anthropic/claude-opus-4-20250514": (15.00, 75.00),
@@ -59,6 +70,8 @@ COSTS: dict[str, tuple[float, float]] = {
59
70
  "openai/gpt-4.1-mini": (0.40, 1.60),
60
71
  "openai/o3": (10.50, 42.00),
61
72
  "openai/o4-mini": (1.10, 4.40),
73
+ "google/gemini-2.5-flash": (0.30, 2.50),
74
+ "google/gemini-2.5-pro": (1.25, 10.00),
62
75
  }
63
76
 
64
77
 
@@ -83,7 +96,7 @@ def estimate_cost(
83
96
  output_tokens: Generated/completion tokens produced
84
97
  cache_read_tokens: Tokens served from cache (discounted)
85
98
  cache_write_tokens: Tokens written to cache (premium)
86
- reasoning_tokens: Tokens spent on internal reasoning (GPT-o series)
99
+ reasoning_tokens: Tokens spent on internal reasoning (GPT-o, Gemini)
87
100
 
88
101
  Returns:
89
102
  Estimated cost in USD (0.0 for unknown/local models)
@@ -31,7 +31,7 @@ class OpenCodeProvider(BaseProvider):
31
31
  # Below require the user's own provider credentials (`opencode auth login`).
32
32
  "anthropic/claude-sonnet-5", "anthropic/claude-opus-4-8", "anthropic/claude-haiku-4-5",
33
33
  "openai/gpt-5.4", "openai/gpt-4.1", "openai/gpt-4.1-mini", "openai/o3", "openai/o4-mini",
34
-
34
+ "google/gemini-2.5-flash", "google/gemini-2.5-pro",
35
35
  ]
36
36
 
37
37
  def __init__(self):
@@ -85,5 +85,11 @@ def _auto_register():
85
85
  except ImportError as e:
86
86
  log.debug("vLLM provider not available: %s", e)
87
87
 
88
+ try:
89
+ from .gemini import GeminiProvider
90
+ register("gemini", GeminiProvider, aliases=["google", "gemini-pro", "gemini-flash"])
91
+ except ImportError as e:
92
+ log.debug("Gemini provider not available: %s", e)
93
+
88
94
 
89
95
  _auto_register()
File without changes
File without changes