gemini-deep-research 0.1.0__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.
- gemini_deep_research-0.1.0/.gitignore +86 -0
- gemini_deep_research-0.1.0/LICENSE +21 -0
- gemini_deep_research-0.1.0/PKG-INFO +172 -0
- gemini_deep_research-0.1.0/README.md +130 -0
- gemini_deep_research-0.1.0/pyproject.toml +173 -0
- gemini_deep_research-0.1.0/src/gdr/__init__.py +7 -0
- gemini_deep_research-0.1.0/src/gdr/__main__.py +13 -0
- gemini_deep_research-0.1.0/src/gdr/cli.py +76 -0
- gemini_deep_research-0.1.0/src/gdr/commands/__init__.py +5 -0
- gemini_deep_research-0.1.0/src/gdr/commands/_common.py +147 -0
- gemini_deep_research-0.1.0/src/gdr/commands/cancel.py +66 -0
- gemini_deep_research-0.1.0/src/gdr/commands/config.py +338 -0
- gemini_deep_research-0.1.0/src/gdr/commands/doctor.py +241 -0
- gemini_deep_research-0.1.0/src/gdr/commands/follow_up.py +78 -0
- gemini_deep_research-0.1.0/src/gdr/commands/ls.py +150 -0
- gemini_deep_research-0.1.0/src/gdr/commands/plan.py +189 -0
- gemini_deep_research-0.1.0/src/gdr/commands/research.py +716 -0
- gemini_deep_research-0.1.0/src/gdr/commands/resume.py +169 -0
- gemini_deep_research-0.1.0/src/gdr/commands/show.py +139 -0
- gemini_deep_research-0.1.0/src/gdr/commands/status.py +106 -0
- gemini_deep_research-0.1.0/src/gdr/config.py +226 -0
- gemini_deep_research-0.1.0/src/gdr/constants.py +56 -0
- gemini_deep_research-0.1.0/src/gdr/core/__init__.py +1 -0
- gemini_deep_research-0.1.0/src/gdr/core/client.py +112 -0
- gemini_deep_research-0.1.0/src/gdr/core/inputs.py +236 -0
- gemini_deep_research-0.1.0/src/gdr/core/models.py +219 -0
- gemini_deep_research-0.1.0/src/gdr/core/persistence.py +184 -0
- gemini_deep_research-0.1.0/src/gdr/core/planning.py +243 -0
- gemini_deep_research-0.1.0/src/gdr/core/rendering.py +420 -0
- gemini_deep_research-0.1.0/src/gdr/core/requests.py +120 -0
- gemini_deep_research-0.1.0/src/gdr/core/security.py +262 -0
- gemini_deep_research-0.1.0/src/gdr/core/streaming.py +372 -0
- gemini_deep_research-0.1.0/src/gdr/errors.py +59 -0
- gemini_deep_research-0.1.0/src/gdr/ui/__init__.py +1 -0
- gemini_deep_research-0.1.0/src/gdr/ui/live.py +218 -0
- gemini_deep_research-0.1.0/src/gdr/ui/progress.py +169 -0
- gemini_deep_research-0.1.0/tests/__init__.py +0 -0
- gemini_deep_research-0.1.0/tests/conftest.py +8 -0
- gemini_deep_research-0.1.0/tests/fixtures/streams/disconnect_mid_text.jsonl +7 -0
- gemini_deep_research-0.1.0/tests/fixtures/streams/happy_path.jsonl +10 -0
- gemini_deep_research-0.1.0/tests/fixtures/streams/mid_stream_error.jsonl +4 -0
- gemini_deep_research-0.1.0/tests/fixtures/streams/out_of_order.jsonl +6 -0
- gemini_deep_research-0.1.0/tests/fixtures/streams/thought_image_text.jsonl +16 -0
- gemini_deep_research-0.1.0/tests/unit/__init__.py +0 -0
- gemini_deep_research-0.1.0/tests/unit/test_cancel_command.py +89 -0
- gemini_deep_research-0.1.0/tests/unit/test_cli.py +36 -0
- gemini_deep_research-0.1.0/tests/unit/test_client.py +77 -0
- gemini_deep_research-0.1.0/tests/unit/test_commands_common.py +77 -0
- gemini_deep_research-0.1.0/tests/unit/test_config.py +188 -0
- gemini_deep_research-0.1.0/tests/unit/test_config_command.py +200 -0
- gemini_deep_research-0.1.0/tests/unit/test_doctor_command.py +170 -0
- gemini_deep_research-0.1.0/tests/unit/test_follow_up_command.py +131 -0
- gemini_deep_research-0.1.0/tests/unit/test_inputs.py +300 -0
- gemini_deep_research-0.1.0/tests/unit/test_live.py +203 -0
- gemini_deep_research-0.1.0/tests/unit/test_ls_command.py +137 -0
- gemini_deep_research-0.1.0/tests/unit/test_models.py +174 -0
- gemini_deep_research-0.1.0/tests/unit/test_persistence.py +171 -0
- gemini_deep_research-0.1.0/tests/unit/test_plan_command.py +274 -0
- gemini_deep_research-0.1.0/tests/unit/test_planning.py +248 -0
- gemini_deep_research-0.1.0/tests/unit/test_progress.py +146 -0
- gemini_deep_research-0.1.0/tests/unit/test_rendering.py +415 -0
- gemini_deep_research-0.1.0/tests/unit/test_requests.py +208 -0
- gemini_deep_research-0.1.0/tests/unit/test_research_command.py +1034 -0
- gemini_deep_research-0.1.0/tests/unit/test_resume_command.py +189 -0
- gemini_deep_research-0.1.0/tests/unit/test_security.py +226 -0
- gemini_deep_research-0.1.0/tests/unit/test_show_command.py +145 -0
- gemini_deep_research-0.1.0/tests/unit/test_status_command.py +130 -0
- gemini_deep_research-0.1.0/tests/unit/test_streaming.py +217 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.egg
|
|
13
|
+
.eggs/
|
|
14
|
+
wheels/
|
|
15
|
+
share/python-wheels/
|
|
16
|
+
MANIFEST
|
|
17
|
+
|
|
18
|
+
# Virtual environments
|
|
19
|
+
venv/
|
|
20
|
+
.venv/
|
|
21
|
+
env/
|
|
22
|
+
ENV/
|
|
23
|
+
.env
|
|
24
|
+
.env.*
|
|
25
|
+
!.env.example
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.nox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
*.py,cover
|
|
46
|
+
.hypothesis/
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
|
|
49
|
+
# Ruff / mypy caches
|
|
50
|
+
.mypy_cache/
|
|
51
|
+
.ruff_cache/
|
|
52
|
+
.dmypy.json
|
|
53
|
+
dmypy.json
|
|
54
|
+
|
|
55
|
+
# uv (note: uv.lock is committed for reproducibility)
|
|
56
|
+
.uv/
|
|
57
|
+
|
|
58
|
+
# Jupyter / IPython
|
|
59
|
+
.ipynb_checkpoints
|
|
60
|
+
profile_default/
|
|
61
|
+
ipython_config.py
|
|
62
|
+
|
|
63
|
+
# Editors / IDEs
|
|
64
|
+
.vscode/
|
|
65
|
+
.idea/
|
|
66
|
+
*.swp
|
|
67
|
+
*.swo
|
|
68
|
+
*.sublime-workspace
|
|
69
|
+
*.sublime-project
|
|
70
|
+
|
|
71
|
+
# OS
|
|
72
|
+
.DS_Store
|
|
73
|
+
Thumbs.db
|
|
74
|
+
Desktop.ini
|
|
75
|
+
|
|
76
|
+
# Claude Code local state
|
|
77
|
+
.claude/
|
|
78
|
+
|
|
79
|
+
# Project-local scratch
|
|
80
|
+
scratch/
|
|
81
|
+
tmp/
|
|
82
|
+
*.log
|
|
83
|
+
|
|
84
|
+
# Local config accidentally copied into repo
|
|
85
|
+
.gdr/
|
|
86
|
+
gdr-reports/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gdr contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gemini-deep-research
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial terminal-first client for Google's Gemini Deep Research and Deep Research Max agents (not affiliated with Google).
|
|
5
|
+
Project-URL: Homepage, https://github.com/johnswyou/gemini-deep-research
|
|
6
|
+
Project-URL: Repository, https://github.com/johnswyou/gemini-deep-research
|
|
7
|
+
Project-URL: Issues, https://github.com/johnswyou/gemini-deep-research/issues
|
|
8
|
+
Author: gdr contributors
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,ai,cli,deep-research,gemini,google,llm,research
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: Software Development
|
|
26
|
+
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: google-genai>=1.55.0
|
|
29
|
+
Requires-Dist: httpx>=0.27.0
|
|
30
|
+
Requires-Dist: platformdirs>=4.2.0
|
|
31
|
+
Requires-Dist: pydantic>=2.7.0
|
|
32
|
+
Requires-Dist: rich>=13.7.0
|
|
33
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
34
|
+
Requires-Dist: typer>=0.12.0
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest-mock>=3.14; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# gdr — Gemini Deep Research CLI
|
|
44
|
+
|
|
45
|
+
> **Status:** Alpha. APIs and commands may change before v1.0.
|
|
46
|
+
|
|
47
|
+
> **Disclaimer:** Unofficial, community-built CLI. Not affiliated with, endorsed by, or sponsored by Google LLC. "Gemini" and "Deep Research" are trademarks of Google LLC, used here nominatively to describe the APIs this tool interacts with.
|
|
48
|
+
|
|
49
|
+
A terminal-first client for Google's **Gemini Deep Research** and **Deep Research Max** agents. Run long-horizon research tasks from your shell and get cleanly organized artifacts — markdown reports, charts, citations, and a full transcript — saved to disk.
|
|
50
|
+
|
|
51
|
+
`gdr` is a thin, honest wrapper over the [`google-genai`](https://github.com/googleapis/python-genai) SDK. The SDK does the work; `gdr` adds ergonomics: streaming UI, safe config/secret management, local history, a collaborative planning flow, resume-after-disconnect, and safe MCP wiring.
|
|
52
|
+
|
|
53
|
+
## Why
|
|
54
|
+
|
|
55
|
+
Deep Research tasks run for 5–60 minutes. Running them from a web UI means keeping a browser tab open. `gdr` decouples the task from your terminal session: start a research run, live-stream thought summaries, walk away, resume later by ID, and get artifacts on disk that fit into any downstream pipeline.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# With pipx (recommended — isolated install)
|
|
61
|
+
pipx install gemini-deep-research
|
|
62
|
+
|
|
63
|
+
# With uv tool
|
|
64
|
+
uv tool install gemini-deep-research
|
|
65
|
+
|
|
66
|
+
# From source (dev)
|
|
67
|
+
git clone https://github.com/johnswyou/gemini-deep-research
|
|
68
|
+
cd gemini-deep-research
|
|
69
|
+
uv sync --extra dev
|
|
70
|
+
uv run gdr --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quickstart
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export GEMINI_API_KEY=... # get one at https://aistudio.google.com/apikey
|
|
77
|
+
|
|
78
|
+
# One-line research with the fast agent
|
|
79
|
+
gdr research "Latest trends in RISC-V adoption"
|
|
80
|
+
|
|
81
|
+
# Maximum-quality agent for due diligence
|
|
82
|
+
gdr research --max "Competitive landscape of EV batteries"
|
|
83
|
+
|
|
84
|
+
# Review and refine the agent's plan before it spends tokens
|
|
85
|
+
gdr research --plan "Impact of AI on semiconductor supply chain"
|
|
86
|
+
|
|
87
|
+
# Ground in your own documents
|
|
88
|
+
gdr research --file ~/Downloads/10k.pdf \
|
|
89
|
+
"Compare risk factors vs our 2024 filing"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Each run produces a timestamped directory under `~/gdr-reports/` containing `report.md`, `sources.json`, `transcript.json`, `metadata.json`, and any generated images.
|
|
93
|
+
|
|
94
|
+
## Command reference
|
|
95
|
+
|
|
96
|
+
| Command | Purpose |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `gdr research <query>` | Run a research task (fast agent by default, `--max` for Max) |
|
|
99
|
+
| `gdr research --plan <query>` | Collaborative planning — review and refine the plan before execution |
|
|
100
|
+
| `gdr status <id>` | Check the status of a running or completed task |
|
|
101
|
+
| `gdr resume <id>` | Re-attach to a running task after Ctrl+C or disconnect |
|
|
102
|
+
| `gdr follow-up <id> <question>` | Ask a follow-up using the previous interaction as context |
|
|
103
|
+
| `gdr plan refine <id> <feedback>` | Iterate on a pending plan without executing |
|
|
104
|
+
| `gdr plan approve <id>` | Approve and execute a pending plan |
|
|
105
|
+
| `gdr cancel <id>` | Cancel a running task |
|
|
106
|
+
| `gdr ls` | List recent interactions |
|
|
107
|
+
| `gdr show <id>` | Render a saved artifact |
|
|
108
|
+
| `gdr config {path,get,set,edit}` | Manage the TOML config file |
|
|
109
|
+
| `gdr doctor [--fix]` | Diagnose and optionally repair your setup |
|
|
110
|
+
|
|
111
|
+
Run `gdr --help` or `gdr <command> --help` for full flag reference.
|
|
112
|
+
|
|
113
|
+
See [`docs/USAGE.md`](docs/USAGE.md) for long-form command documentation,
|
|
114
|
+
[`docs/MCP.md`](docs/MCP.md) for MCP server integration, and
|
|
115
|
+
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for common failure
|
|
116
|
+
modes and recovery recipes. Runnable demos live in [`examples/`](examples/).
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
Config lives at `~/.config/gdr/config.toml`. Run `gdr doctor --fix` to scaffold it. Environment variables referenced with `env:VAR_NAME` are expanded at load time so secrets stay out of the file.
|
|
121
|
+
|
|
122
|
+
```toml
|
|
123
|
+
api_key = "env:GEMINI_API_KEY"
|
|
124
|
+
default_agent = "deep-research-preview-04-2026"
|
|
125
|
+
output_dir = "~/gdr-reports"
|
|
126
|
+
auto_open = true
|
|
127
|
+
confirm_max = true # prompt before running the Max agent
|
|
128
|
+
default_tools = ["google_search", "url_context", "code_execution"]
|
|
129
|
+
thinking_summaries = "auto" # "auto" or "none"
|
|
130
|
+
visualization = "auto" # "auto" or "off"
|
|
131
|
+
safe_untrusted = true # auto-strip dangerous tools when --file/--url is used
|
|
132
|
+
|
|
133
|
+
[mcp_servers.factset]
|
|
134
|
+
url = "https://mcp.factset.com"
|
|
135
|
+
headers.Authorization = "Bearer env:FACTSET_TOKEN"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Safety
|
|
139
|
+
|
|
140
|
+
Deep Research agents can read files and the public web. `gdr` ships with:
|
|
141
|
+
|
|
142
|
+
- **Redaction** of MCP auth headers and API keys from `transcript.json`.
|
|
143
|
+
- **Path confinement**: all artifacts land under the configured `output_dir`; slug names are sanitized.
|
|
144
|
+
- **Header validation** for MCP servers (no CRLF injection, no reserved names).
|
|
145
|
+
- **`--untrusted-input`** flag that disables `code_execution` and `mcp_server` tools for a run — use when grounding in attacker-controlled files or URLs.
|
|
146
|
+
|
|
147
|
+
See [`docs/MCP.md`](docs/MCP.md) for the MCP security model and
|
|
148
|
+
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for the
|
|
149
|
+
`--untrusted-input` recipe.
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
uv sync --extra dev
|
|
155
|
+
uv run ruff check .
|
|
156
|
+
uv run mypy src
|
|
157
|
+
uv run pytest -q
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Roadmap
|
|
161
|
+
|
|
162
|
+
Deferred to v1.1: HTML/PDF export, cost estimation, SQLite history
|
|
163
|
+
backend, interactive setup wizard. See `docs/USAGE.md` for the
|
|
164
|
+
currently-shipping surface.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
169
|
+
|
|
170
|
+
## Credits
|
|
171
|
+
|
|
172
|
+
Built on [Google's Gemini Interactions API](https://ai.google.dev/gemini-api/docs/interactions) and the [`google-genai`](https://github.com/googleapis/python-genai) Python SDK.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# gdr — Gemini Deep Research CLI
|
|
2
|
+
|
|
3
|
+
> **Status:** Alpha. APIs and commands may change before v1.0.
|
|
4
|
+
|
|
5
|
+
> **Disclaimer:** Unofficial, community-built CLI. Not affiliated with, endorsed by, or sponsored by Google LLC. "Gemini" and "Deep Research" are trademarks of Google LLC, used here nominatively to describe the APIs this tool interacts with.
|
|
6
|
+
|
|
7
|
+
A terminal-first client for Google's **Gemini Deep Research** and **Deep Research Max** agents. Run long-horizon research tasks from your shell and get cleanly organized artifacts — markdown reports, charts, citations, and a full transcript — saved to disk.
|
|
8
|
+
|
|
9
|
+
`gdr` is a thin, honest wrapper over the [`google-genai`](https://github.com/googleapis/python-genai) SDK. The SDK does the work; `gdr` adds ergonomics: streaming UI, safe config/secret management, local history, a collaborative planning flow, resume-after-disconnect, and safe MCP wiring.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Deep Research tasks run for 5–60 minutes. Running them from a web UI means keeping a browser tab open. `gdr` decouples the task from your terminal session: start a research run, live-stream thought summaries, walk away, resume later by ID, and get artifacts on disk that fit into any downstream pipeline.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# With pipx (recommended — isolated install)
|
|
19
|
+
pipx install gemini-deep-research
|
|
20
|
+
|
|
21
|
+
# With uv tool
|
|
22
|
+
uv tool install gemini-deep-research
|
|
23
|
+
|
|
24
|
+
# From source (dev)
|
|
25
|
+
git clone https://github.com/johnswyou/gemini-deep-research
|
|
26
|
+
cd gemini-deep-research
|
|
27
|
+
uv sync --extra dev
|
|
28
|
+
uv run gdr --help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quickstart
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export GEMINI_API_KEY=... # get one at https://aistudio.google.com/apikey
|
|
35
|
+
|
|
36
|
+
# One-line research with the fast agent
|
|
37
|
+
gdr research "Latest trends in RISC-V adoption"
|
|
38
|
+
|
|
39
|
+
# Maximum-quality agent for due diligence
|
|
40
|
+
gdr research --max "Competitive landscape of EV batteries"
|
|
41
|
+
|
|
42
|
+
# Review and refine the agent's plan before it spends tokens
|
|
43
|
+
gdr research --plan "Impact of AI on semiconductor supply chain"
|
|
44
|
+
|
|
45
|
+
# Ground in your own documents
|
|
46
|
+
gdr research --file ~/Downloads/10k.pdf \
|
|
47
|
+
"Compare risk factors vs our 2024 filing"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each run produces a timestamped directory under `~/gdr-reports/` containing `report.md`, `sources.json`, `transcript.json`, `metadata.json`, and any generated images.
|
|
51
|
+
|
|
52
|
+
## Command reference
|
|
53
|
+
|
|
54
|
+
| Command | Purpose |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `gdr research <query>` | Run a research task (fast agent by default, `--max` for Max) |
|
|
57
|
+
| `gdr research --plan <query>` | Collaborative planning — review and refine the plan before execution |
|
|
58
|
+
| `gdr status <id>` | Check the status of a running or completed task |
|
|
59
|
+
| `gdr resume <id>` | Re-attach to a running task after Ctrl+C or disconnect |
|
|
60
|
+
| `gdr follow-up <id> <question>` | Ask a follow-up using the previous interaction as context |
|
|
61
|
+
| `gdr plan refine <id> <feedback>` | Iterate on a pending plan without executing |
|
|
62
|
+
| `gdr plan approve <id>` | Approve and execute a pending plan |
|
|
63
|
+
| `gdr cancel <id>` | Cancel a running task |
|
|
64
|
+
| `gdr ls` | List recent interactions |
|
|
65
|
+
| `gdr show <id>` | Render a saved artifact |
|
|
66
|
+
| `gdr config {path,get,set,edit}` | Manage the TOML config file |
|
|
67
|
+
| `gdr doctor [--fix]` | Diagnose and optionally repair your setup |
|
|
68
|
+
|
|
69
|
+
Run `gdr --help` or `gdr <command> --help` for full flag reference.
|
|
70
|
+
|
|
71
|
+
See [`docs/USAGE.md`](docs/USAGE.md) for long-form command documentation,
|
|
72
|
+
[`docs/MCP.md`](docs/MCP.md) for MCP server integration, and
|
|
73
|
+
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for common failure
|
|
74
|
+
modes and recovery recipes. Runnable demos live in [`examples/`](examples/).
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
Config lives at `~/.config/gdr/config.toml`. Run `gdr doctor --fix` to scaffold it. Environment variables referenced with `env:VAR_NAME` are expanded at load time so secrets stay out of the file.
|
|
79
|
+
|
|
80
|
+
```toml
|
|
81
|
+
api_key = "env:GEMINI_API_KEY"
|
|
82
|
+
default_agent = "deep-research-preview-04-2026"
|
|
83
|
+
output_dir = "~/gdr-reports"
|
|
84
|
+
auto_open = true
|
|
85
|
+
confirm_max = true # prompt before running the Max agent
|
|
86
|
+
default_tools = ["google_search", "url_context", "code_execution"]
|
|
87
|
+
thinking_summaries = "auto" # "auto" or "none"
|
|
88
|
+
visualization = "auto" # "auto" or "off"
|
|
89
|
+
safe_untrusted = true # auto-strip dangerous tools when --file/--url is used
|
|
90
|
+
|
|
91
|
+
[mcp_servers.factset]
|
|
92
|
+
url = "https://mcp.factset.com"
|
|
93
|
+
headers.Authorization = "Bearer env:FACTSET_TOKEN"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Safety
|
|
97
|
+
|
|
98
|
+
Deep Research agents can read files and the public web. `gdr` ships with:
|
|
99
|
+
|
|
100
|
+
- **Redaction** of MCP auth headers and API keys from `transcript.json`.
|
|
101
|
+
- **Path confinement**: all artifacts land under the configured `output_dir`; slug names are sanitized.
|
|
102
|
+
- **Header validation** for MCP servers (no CRLF injection, no reserved names).
|
|
103
|
+
- **`--untrusted-input`** flag that disables `code_execution` and `mcp_server` tools for a run — use when grounding in attacker-controlled files or URLs.
|
|
104
|
+
|
|
105
|
+
See [`docs/MCP.md`](docs/MCP.md) for the MCP security model and
|
|
106
|
+
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for the
|
|
107
|
+
`--untrusted-input` recipe.
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv sync --extra dev
|
|
113
|
+
uv run ruff check .
|
|
114
|
+
uv run mypy src
|
|
115
|
+
uv run pytest -q
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Roadmap
|
|
119
|
+
|
|
120
|
+
Deferred to v1.1: HTML/PDF export, cost estimation, SQLite history
|
|
121
|
+
backend, interactive setup wizard. See `docs/USAGE.md` for the
|
|
122
|
+
currently-shipping surface.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
127
|
+
|
|
128
|
+
## Credits
|
|
129
|
+
|
|
130
|
+
Built on [Google's Gemini Interactions API](https://ai.google.dev/gemini-api/docs/interactions) and the [`google-genai`](https://github.com/googleapis/python-genai) Python SDK.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gemini-deep-research"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unofficial terminal-first client for Google's Gemini Deep Research and Deep Research Max agents (not affiliated with Google)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "gdr contributors" }]
|
|
13
|
+
keywords = ["gemini", "deep-research", "cli", "llm", "google", "ai", "research", "agent"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
28
|
+
"Topic :: Software Development",
|
|
29
|
+
"Topic :: Utilities",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"google-genai>=1.55.0",
|
|
33
|
+
"typer>=0.12.0",
|
|
34
|
+
"rich>=13.7.0",
|
|
35
|
+
"pydantic>=2.7.0",
|
|
36
|
+
"platformdirs>=4.2.0",
|
|
37
|
+
"httpx>=0.27.0",
|
|
38
|
+
"tomli>=2.0.0; python_version < '3.11'",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"pytest>=8.0",
|
|
44
|
+
"pytest-cov>=5.0",
|
|
45
|
+
"pytest-mock>=3.14",
|
|
46
|
+
"ruff>=0.6",
|
|
47
|
+
"mypy>=1.10",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[project.scripts]
|
|
51
|
+
gdr = "gdr.cli:app"
|
|
52
|
+
|
|
53
|
+
[project.urls]
|
|
54
|
+
Homepage = "https://github.com/johnswyou/gemini-deep-research"
|
|
55
|
+
Repository = "https://github.com/johnswyou/gemini-deep-research"
|
|
56
|
+
Issues = "https://github.com/johnswyou/gemini-deep-research/issues"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.wheel]
|
|
59
|
+
packages = ["src/gdr"]
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.sdist]
|
|
62
|
+
include = [
|
|
63
|
+
"src/gdr",
|
|
64
|
+
"tests",
|
|
65
|
+
"README.md",
|
|
66
|
+
"LICENSE",
|
|
67
|
+
"pyproject.toml",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# Ruff (lint + format)
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
[tool.ruff]
|
|
74
|
+
line-length = 100
|
|
75
|
+
target-version = "py310"
|
|
76
|
+
src = ["src", "tests"]
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
select = [
|
|
80
|
+
"E", # pycodestyle errors
|
|
81
|
+
"W", # pycodestyle warnings
|
|
82
|
+
"F", # pyflakes
|
|
83
|
+
"I", # isort
|
|
84
|
+
"B", # flake8-bugbear
|
|
85
|
+
"UP", # pyupgrade
|
|
86
|
+
"N", # pep8-naming
|
|
87
|
+
"RUF", # ruff-specific
|
|
88
|
+
"SIM", # flake8-simplify
|
|
89
|
+
"PTH", # flake8-use-pathlib
|
|
90
|
+
"C4", # flake8-comprehensions
|
|
91
|
+
"PL", # pylint
|
|
92
|
+
"TID", # flake8-tidy-imports
|
|
93
|
+
]
|
|
94
|
+
ignore = [
|
|
95
|
+
"E501", # line length handled by formatter
|
|
96
|
+
"PLR0913", # too many arguments — CLI commands legitimately have many
|
|
97
|
+
"PLR2004", # magic value comparisons — readable in tests
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.lint.per-file-ignores]
|
|
101
|
+
"tests/**" = ["PLR", "B011"]
|
|
102
|
+
"src/gdr/cli.py" = ["PLC0415"]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.flake8-bugbear]
|
|
105
|
+
# Typer's idiom requires `typer.Option(...)` / `typer.Argument(...)` in
|
|
106
|
+
# default values of command functions. These calls are side-effect-free
|
|
107
|
+
# metadata constructors, so the bugbear B008 warning is spurious here.
|
|
108
|
+
extend-immutable-calls = ["typer.Option", "typer.Argument"]
|
|
109
|
+
|
|
110
|
+
[tool.ruff.format]
|
|
111
|
+
quote-style = "double"
|
|
112
|
+
|
|
113
|
+
# ---------------------------------------------------------------------------
|
|
114
|
+
# Mypy (strict typing)
|
|
115
|
+
# ---------------------------------------------------------------------------
|
|
116
|
+
[tool.mypy]
|
|
117
|
+
python_version = "3.10"
|
|
118
|
+
strict = true
|
|
119
|
+
warn_unused_ignores = true
|
|
120
|
+
warn_return_any = true
|
|
121
|
+
disallow_untyped_defs = true
|
|
122
|
+
disallow_any_generics = true
|
|
123
|
+
no_implicit_optional = true
|
|
124
|
+
check_untyped_defs = true
|
|
125
|
+
pretty = true
|
|
126
|
+
show_error_codes = true
|
|
127
|
+
mypy_path = "src"
|
|
128
|
+
packages = ["gdr"]
|
|
129
|
+
explicit_package_bases = true
|
|
130
|
+
|
|
131
|
+
[[tool.mypy.overrides]]
|
|
132
|
+
module = ["google.*", "google.genai.*"]
|
|
133
|
+
ignore_missing_imports = true
|
|
134
|
+
|
|
135
|
+
[[tool.mypy.overrides]]
|
|
136
|
+
# `tomli` is only imported on Python 3.10; we run mypy on 3.11+.
|
|
137
|
+
module = "tomli"
|
|
138
|
+
ignore_missing_imports = true
|
|
139
|
+
|
|
140
|
+
[[tool.mypy.overrides]]
|
|
141
|
+
module = "tests.*"
|
|
142
|
+
disallow_untyped_defs = false
|
|
143
|
+
|
|
144
|
+
# ---------------------------------------------------------------------------
|
|
145
|
+
# Pytest
|
|
146
|
+
# ---------------------------------------------------------------------------
|
|
147
|
+
[tool.pytest.ini_options]
|
|
148
|
+
minversion = "8.0"
|
|
149
|
+
addopts = [
|
|
150
|
+
"-ra",
|
|
151
|
+
"--strict-markers",
|
|
152
|
+
"--strict-config",
|
|
153
|
+
]
|
|
154
|
+
testpaths = ["tests"]
|
|
155
|
+
pythonpath = ["src"]
|
|
156
|
+
markers = [
|
|
157
|
+
"live: tests that hit the real Gemini API (requires GEMINI_API_KEY and RUN_LIVE_TESTS=1)",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
# Coverage
|
|
162
|
+
# ---------------------------------------------------------------------------
|
|
163
|
+
[tool.coverage.run]
|
|
164
|
+
source = ["src/gdr"]
|
|
165
|
+
branch = true
|
|
166
|
+
|
|
167
|
+
[tool.coverage.report]
|
|
168
|
+
exclude_lines = [
|
|
169
|
+
"pragma: no cover",
|
|
170
|
+
"raise NotImplementedError",
|
|
171
|
+
"if TYPE_CHECKING:",
|
|
172
|
+
"if __name__ == .__main__.:",
|
|
173
|
+
]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Typer app root for the gdr CLI.
|
|
2
|
+
|
|
3
|
+
This module wires up the top-level application and registers subcommands.
|
|
4
|
+
Subcommands live in `gdr.commands.*` and are added here as each phase lands.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from gdr import __version__
|
|
12
|
+
from gdr.commands import (
|
|
13
|
+
cancel,
|
|
14
|
+
doctor,
|
|
15
|
+
follow_up,
|
|
16
|
+
ls,
|
|
17
|
+
plan,
|
|
18
|
+
research,
|
|
19
|
+
resume,
|
|
20
|
+
show,
|
|
21
|
+
status,
|
|
22
|
+
)
|
|
23
|
+
from gdr.commands import (
|
|
24
|
+
config as config_cmd,
|
|
25
|
+
)
|
|
26
|
+
from gdr.constants import APP_DESCRIPTION, APP_NAME
|
|
27
|
+
|
|
28
|
+
app = typer.Typer(
|
|
29
|
+
name=APP_NAME,
|
|
30
|
+
help=APP_DESCRIPTION,
|
|
31
|
+
no_args_is_help=True,
|
|
32
|
+
add_completion=True,
|
|
33
|
+
rich_markup_mode="rich",
|
|
34
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _version_callback(value: bool) -> None:
|
|
39
|
+
if value:
|
|
40
|
+
typer.echo(f"{APP_NAME} {__version__}")
|
|
41
|
+
raise typer.Exit
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.callback()
|
|
45
|
+
def main(
|
|
46
|
+
_version: bool = typer.Option(
|
|
47
|
+
False,
|
|
48
|
+
"--version",
|
|
49
|
+
"-V",
|
|
50
|
+
callback=_version_callback,
|
|
51
|
+
is_eager=True,
|
|
52
|
+
help="Show the installed gdr version and exit.",
|
|
53
|
+
),
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Gemini Deep Research from your terminal.
|
|
56
|
+
|
|
57
|
+
Run `gdr research <query>` to start. See `gdr --help` for the full command
|
|
58
|
+
list once more commands are registered in later phases.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Subcommands — each module exposes a `run` function or a Typer sub-app.
|
|
63
|
+
app.command(name="research", help="Run a Deep Research task and save artifacts to disk.")(
|
|
64
|
+
research.run
|
|
65
|
+
)
|
|
66
|
+
app.add_typer(plan.app, name="plan")
|
|
67
|
+
app.command(name="ls", help="List recent interactions from the local store.")(ls.run)
|
|
68
|
+
app.command(name="show", help="Print a saved artifact from a prior research run.")(show.run)
|
|
69
|
+
app.command(name="status", help="Check the current status of an interaction.")(status.run)
|
|
70
|
+
app.command(name="resume", help="Reattach to a running or completed interaction.")(resume.run)
|
|
71
|
+
app.command(
|
|
72
|
+
name="follow-up", help="Ask a follow-up question using a prior interaction as context."
|
|
73
|
+
)(follow_up.run)
|
|
74
|
+
app.command(name="cancel", help="Cancel an in-progress interaction.")(cancel.run)
|
|
75
|
+
app.add_typer(config_cmd.app, name="config")
|
|
76
|
+
app.command(name="doctor", help="Validate the local environment for gdr.")(doctor.run)
|