gemcode 0.3.106__tar.gz → 0.3.108__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.
- {gemcode-0.3.106/src/gemcode.egg-info → gemcode-0.3.108}/PKG-INFO +13 -1
- {gemcode-0.3.106 → gemcode-0.3.108}/README.md +12 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/pyproject.toml +1 -1
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/agent.py +87 -2
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/cli.py +29 -4
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/config.py +25 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/invoke.py +14 -10
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/kaira_daemon.py +6 -2
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/model_errors.py +18 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/repl_commands.py +2 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/repl_slash.py +17 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tool_prompt_manifest.py +35 -1
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tool_registry.py +3 -1
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/subtask.py +3 -2
- gemcode-0.3.108/src/gemcode/tools/user_choice.py +58 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tui/scrollback.py +100 -48
- {gemcode-0.3.106 → gemcode-0.3.108/src/gemcode.egg-info}/PKG-INFO +13 -1
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode.egg-info/SOURCES.txt +1 -0
- gemcode-0.3.108/tests/test_agent_instruction.py +76 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_model_errors.py +17 -1
- gemcode-0.3.106/tests/test_agent_instruction.py +0 -22
- {gemcode-0.3.106 → gemcode-0.3.108}/LICENSE +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/MANIFEST.in +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/setup.cfg +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/autotune.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/callbacks.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/checkpoints.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/curated_memory.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/dynamic_policy.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/evals/harness.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/ide_protocol.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/ide_stdio.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/kaira_client.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/kaira_ipc.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/kaira_job_store.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/learning.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/multimodal_input.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/org.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/output_styles.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/policy_profile.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/query_sanitizer.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/rules.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/session_runtime.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/session_summariser.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/skills.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tool_result_store.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/compress_memory.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/curated_memory.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/notebook.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/org_tools.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/repo_map.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/skills.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/tasks.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/veomem_tools.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools/web_search.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/veomem_bridge.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/version.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/wal.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/web/sse_adapter.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/web/web_sse_compat.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_add_dir.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_checkpoint_diff_command.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_compress_memory_tool.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_credentials.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_eval_harness_layout.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_ide_stdio_attachments.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_kaira_scheduler.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_multimodal_input.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_output_styles_and_rules.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_paths.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_permissions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_skills.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_slash_completion_registry.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_tools.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_web_sse_adapter.py +0 -0
- {gemcode-0.3.106 → gemcode-0.3.108}/tests/test_workspace_hints.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gemcode
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.108
|
|
4
4
|
Summary: Local-first coding agent on Google Gemini + ADK
|
|
5
5
|
Author: GemCode Contributors
|
|
6
6
|
License: Apache License
|
|
@@ -327,6 +327,17 @@ GemCode combines:
|
|
|
327
327
|
Reference:
|
|
328
328
|
- [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md)
|
|
329
329
|
|
|
330
|
+
### Super mode (fully autonomous)
|
|
331
|
+
|
|
332
|
+
Use when you want GemCode to run without GemCode’s own confirmation prompts (mutations, shell, ADK confirmation handoffs, AFC stdin prompt, attachment gate, auto-trust on CLI, and non-interactive `get_user_choice` = first option).
|
|
333
|
+
|
|
334
|
+
- **CLI:** `gemcode -C . --super "your task"`
|
|
335
|
+
- **Env:** `GEMCODE_SUPER_MODE=1`
|
|
336
|
+
- **REPL/TUI:** `/super` (use `/super off` to clear the flag only)
|
|
337
|
+
- **Kaira:** `gemcode kaira -C . --super`
|
|
338
|
+
|
|
339
|
+
Details and safety notes: [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md#super-mode-fully-autonomous).
|
|
340
|
+
|
|
330
341
|
## Common commands
|
|
331
342
|
|
|
332
343
|
### Inspect models
|
|
@@ -410,6 +421,7 @@ Status note:
|
|
|
410
421
|
| `/review` | Run a review workflow |
|
|
411
422
|
| `/eval` | Run evaluation gates |
|
|
412
423
|
| `/kaira` | Show scheduler usage help |
|
|
424
|
+
| `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
|
|
413
425
|
|
|
414
426
|
Detailed behavior:
|
|
415
427
|
- [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
|
|
@@ -135,6 +135,17 @@ GemCode combines:
|
|
|
135
135
|
Reference:
|
|
136
136
|
- [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md)
|
|
137
137
|
|
|
138
|
+
### Super mode (fully autonomous)
|
|
139
|
+
|
|
140
|
+
Use when you want GemCode to run without GemCode’s own confirmation prompts (mutations, shell, ADK confirmation handoffs, AFC stdin prompt, attachment gate, auto-trust on CLI, and non-interactive `get_user_choice` = first option).
|
|
141
|
+
|
|
142
|
+
- **CLI:** `gemcode -C . --super "your task"`
|
|
143
|
+
- **Env:** `GEMCODE_SUPER_MODE=1`
|
|
144
|
+
- **REPL/TUI:** `/super` (use `/super off` to clear the flag only)
|
|
145
|
+
- **Kaira:** `gemcode kaira -C . --super`
|
|
146
|
+
|
|
147
|
+
Details and safety notes: [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md#super-mode-fully-autonomous).
|
|
148
|
+
|
|
138
149
|
## Common commands
|
|
139
150
|
|
|
140
151
|
### Inspect models
|
|
@@ -218,6 +229,7 @@ Status note:
|
|
|
218
229
|
| `/review` | Run a review workflow |
|
|
219
230
|
| `/eval` | Run evaluation gates |
|
|
220
231
|
| `/kaira` | Show scheduler usage help |
|
|
232
|
+
| `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
|
|
221
233
|
|
|
222
234
|
Detailed behavior:
|
|
223
235
|
- [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
|
|
@@ -76,6 +76,8 @@ def build_global_instruction() -> str:
|
|
|
76
76
|
"You are GemCode, an expert software engineering agent powered by Google Gemini. "
|
|
77
77
|
"Think deeply about what the person actually wants before you do anything. "
|
|
78
78
|
"Use exactly as many tools as the task genuinely requires — no more. "
|
|
79
|
+
"When routing or capabilities change between turns, still prefer minimal tools, "
|
|
80
|
+
"repo-grounded evidence, and verification before claiming done. "
|
|
79
81
|
"Act fully and autonomously when action is needed. "
|
|
80
82
|
"Always use read-only tools before shell or write tools. "
|
|
81
83
|
"Never create CLAUDE.md or AGENTS.md; use GEMINI.md for project instructions."
|
|
@@ -353,6 +355,79 @@ def _build_runtime_facts(cfg: GemCodeConfig) -> str:
|
|
|
353
355
|
- **Working in subfolders** — call `list_directory(\"Desktop\")`, `glob_files(\"**/query.ts\")`, `read_file(\"testing/ai-edtech-app/src/app/page.tsx\")` directly. Never claim access is blocked unless a tool returned an explicit error.{git_section}{curated_section}{veomem_section}"""
|
|
354
356
|
|
|
355
357
|
|
|
358
|
+
def _build_calibration_section(cfg: GemCodeConfig) -> str:
|
|
359
|
+
"""
|
|
360
|
+
Meta-instruction for "smart" behavior under dynamic routing (auto model/capability mode,
|
|
361
|
+
orchestration tools, etc.). Kept compact to limit prompt bloat.
|
|
362
|
+
"""
|
|
363
|
+
mm = (getattr(cfg, "model_mode", "") or "").strip().lower()
|
|
364
|
+
cm = (getattr(cfg, "capability_mode", "") or "").strip().lower()
|
|
365
|
+
bits: list[str] = []
|
|
366
|
+
if mm == "auto":
|
|
367
|
+
bits.append("`model_mode=auto` (model may shift per turn for speed vs depth)")
|
|
368
|
+
if cm == "auto":
|
|
369
|
+
bits.append("`capability_mode=auto` (deep research / extras may attach per turn)")
|
|
370
|
+
session_note = ""
|
|
371
|
+
if bits:
|
|
372
|
+
session_note = (
|
|
373
|
+
"\n**This session uses dynamic routing:** "
|
|
374
|
+
+ " · ".join(bits)
|
|
375
|
+
+ ". Defaults are **hints** — override with judgment when the task clearly needs more or less depth.\n"
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return f"""## Calibration and dynamic routing (all modes)
|
|
379
|
+
|
|
380
|
+
Infer **intent → depth → tools** without fixed buckets (requests vary):
|
|
381
|
+
|
|
382
|
+
| Stance | Move |
|
|
383
|
+
| --- | --- |
|
|
384
|
+
| **Explain / review** | Read-only recon first; cite **paths**; avoid unrelated edits. |
|
|
385
|
+
| **Implement / fix** | Recon → plan (`todo_write` when 3+ steps) → smallest change → **verify** (tests, lint, build slice, or read-back). |
|
|
386
|
+
| **Debug** | One hypothesis per iteration; change one variable between tries; never repeat the same failing command verbatim. |
|
|
387
|
+
| **External facts** | Use web/research tools when the answer is outside the repo (docs, APIs, CVEs). Prefer **repo files** for how *this* codebase behaves. |
|
|
388
|
+
|
|
389
|
+
**Evidence:** tie non-obvious claims about this workspace to **files or command output** you actually saw.
|
|
390
|
+
|
|
391
|
+
**Orchestration:** use `spawn_subtasks`, org delegation, or background jobs only when work is **parallel** or **role-split**. Merge into **one** answer with a single recommendation; skip fan-out for small linear tasks.
|
|
392
|
+
|
|
393
|
+
**Anti-patterns:** tool spam; “done” without verification on risky edits; searching the web when the source file is already in-tree; repeating identical failures.{session_note}"""
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _engineering_discipline_instruction_enabled() -> bool:
|
|
397
|
+
"""Extra prompt section: cautious change quality. Opt out with GEMCODE_ENGINEERING_DISCIPLINE=0."""
|
|
398
|
+
import os
|
|
399
|
+
|
|
400
|
+
v = os.environ.get("GEMCODE_ENGINEERING_DISCIPLINE", "1").strip().lower()
|
|
401
|
+
return v not in ("0", "false", "no", "off")
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _build_engineering_discipline_section(cfg: GemCodeConfig) -> str:
|
|
405
|
+
"""Prompt block for minimal, evidence-grounded edits; trivial fixes need not dwell on it."""
|
|
406
|
+
_ = cfg # reserved for future project-scoped tuning
|
|
407
|
+
return """## Engineering discipline (change quality)
|
|
408
|
+
|
|
409
|
+
**Tradeoff:** biases toward careful, minimal diffs over speed. For trivial edits, use judgment.
|
|
410
|
+
|
|
411
|
+
### Ambiguity
|
|
412
|
+
- Briefly state **what you understood** before substantial implementation. If several readings fit, outline them or ask **one** precise question — do not silently pick and run.
|
|
413
|
+
- Prefer **evidence from this repo** (reads, grep, tests) over guessed APIs, paths, or behaviour.
|
|
414
|
+
|
|
415
|
+
### Scope and simplicity
|
|
416
|
+
- Deliver **what was asked**, not a roadmap of extras. Avoid speculative features, abstraction layers, or configurability “for later” unless the user requested flexibility.
|
|
417
|
+
- Prefer the **smallest** correct change. Expand structure only when complexity is already present or clearly required.
|
|
418
|
+
|
|
419
|
+
### Surgical edits
|
|
420
|
+
- Change **only** what is necessary for the outcome; match surrounding **style and patterns** unless project docs say otherwise.
|
|
421
|
+
- Do not refactor, rename, or reformat unrelated code in the same pass. Note worthwhile cleanups separately if helpful.
|
|
422
|
+
- Remove **orphans your edit introduced** (e.g. unused imports from your change). Leave pre-existing dead code unless the user asks to remove it.
|
|
423
|
+
|
|
424
|
+
### When to call it done
|
|
425
|
+
- Turn fuzzy requests into **checkable** outcomes where it matters (e.g. bug → reproduce → fix → same checks green).
|
|
426
|
+
- After material edits, run the **cheapest** falsifying step you can: targeted test, lint, build, or re-read the critical path — not guess-and-hope.
|
|
427
|
+
|
|
428
|
+
"""
|
|
429
|
+
|
|
430
|
+
|
|
356
431
|
def _build_memory_section(cfg: GemCodeConfig) -> str:
|
|
357
432
|
"""Injected when enable_memory=True so the agent understands and uses memory."""
|
|
358
433
|
mem_path = cfg.project_root / ".gemcode" / "memories.jsonl"
|
|
@@ -559,6 +634,12 @@ def build_instruction(cfg: GemCodeConfig) -> str:
|
|
|
559
634
|
"on",
|
|
560
635
|
)
|
|
561
636
|
|
|
637
|
+
discipline_block = (
|
|
638
|
+
_build_engineering_discipline_section(cfg)
|
|
639
|
+
if _engineering_discipline_instruction_enabled()
|
|
640
|
+
else ""
|
|
641
|
+
)
|
|
642
|
+
|
|
562
643
|
base = f"""You are GemCode, an expert software engineering agent powered by Google Gemini.
|
|
563
644
|
You run locally via the GemCode CLI. You are the same agent the user launched — not a hosted portal.
|
|
564
645
|
|
|
@@ -610,6 +691,8 @@ You have native deep thinking capability — use it actively:
|
|
|
610
691
|
- Prefer **small, targeted tool outputs** by default (saves context, improves accuracy).
|
|
611
692
|
- If a tool output was **offloaded** (you see a `tool_result:<sha>` reference), and you need details, call `load_tool_result(ref)` and extract only the relevant slice.
|
|
612
693
|
|
|
694
|
+
{_build_calibration_section(cfg)}
|
|
695
|
+
{discipline_block}
|
|
613
696
|
## Tool selection guide (only when needed)
|
|
614
697
|
|
|
615
698
|
Keep tool usage minimal. Prefer short, targeted calls and keep tool outputs small.
|
|
@@ -1013,9 +1096,11 @@ def build_root_agent(
|
|
|
1013
1096
|
tools = [preload_memory, *tools]
|
|
1014
1097
|
|
|
1015
1098
|
# ADK built-in interactive + artifact tools — always available when ADK supports them.
|
|
1099
|
+
# In super mode, ``get_user_choice`` auto-picks the first option (no UI).
|
|
1016
1100
|
try:
|
|
1017
|
-
from
|
|
1018
|
-
|
|
1101
|
+
from gemcode.tools.user_choice import append_user_choice_load_artifacts_exit_loop
|
|
1102
|
+
|
|
1103
|
+
append_user_choice_load_artifacts_exit_loop(cfg, tools)
|
|
1019
1104
|
except Exception:
|
|
1020
1105
|
pass
|
|
1021
1106
|
|
|
@@ -13,7 +13,7 @@ import uuid
|
|
|
13
13
|
import warnings
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
from gemcode.config import GemCodeConfig, load_cli_environment
|
|
16
|
+
from gemcode.config import GemCodeConfig, apply_super_mode, load_cli_environment
|
|
17
17
|
from gemcode.tools_inspector import inspect_tools, smoke_tools
|
|
18
18
|
from gemcode.invoke import run_turn
|
|
19
19
|
from gemcode.model_routing import pick_effective_model
|
|
@@ -43,6 +43,11 @@ def _maybe_prompt_trust(cfg: GemCodeConfig) -> None:
|
|
|
43
43
|
On first use in a project root, ask the user to trust the folder so file,
|
|
44
44
|
shell, and git tools can run. If not trusted, we exit before any tool runs.
|
|
45
45
|
"""
|
|
46
|
+
if getattr(cfg, "super_mode", False):
|
|
47
|
+
root = cfg.project_root.resolve()
|
|
48
|
+
if not is_trusted_root(root):
|
|
49
|
+
trust_root(root, trusted=True)
|
|
50
|
+
return
|
|
46
51
|
# Non-interactive sessions can't answer prompts.
|
|
47
52
|
if not (hasattr(sys.stdin, "isatty") and sys.stdin.isatty()):
|
|
48
53
|
return
|
|
@@ -220,7 +225,9 @@ async def _run_repl(cfg: GemCodeConfig, session_id: str, *, use_mcp: bool) -> No
|
|
|
220
225
|
"on",
|
|
221
226
|
):
|
|
222
227
|
try:
|
|
223
|
-
if (
|
|
228
|
+
if getattr(cfg, "super_mode", False):
|
|
229
|
+
pass
|
|
230
|
+
elif (
|
|
224
231
|
hasattr(sys.stdin, "isatty")
|
|
225
232
|
and sys.stdin.isatty()
|
|
226
233
|
and not cfg.yes_to_all
|
|
@@ -922,6 +929,11 @@ def main() -> None:
|
|
|
922
929
|
action="store_true",
|
|
923
930
|
help="Allow write_file / search_replace (disables interactive HITL prompts).",
|
|
924
931
|
)
|
|
932
|
+
kaira_parser.add_argument(
|
|
933
|
+
"--super",
|
|
934
|
+
action="store_true",
|
|
935
|
+
help="Fully autonomous jobs: auto-approve tools/shell, no HITL (implies --yes).",
|
|
936
|
+
)
|
|
925
937
|
kaira_parser.add_argument(
|
|
926
938
|
"--interactive-ask",
|
|
927
939
|
action="store_true",
|
|
@@ -978,7 +990,11 @@ def main() -> None:
|
|
|
978
990
|
cfg.model_mode = "fast"
|
|
979
991
|
|
|
980
992
|
cfg.yes_to_all = bool(args.yes)
|
|
981
|
-
if args
|
|
993
|
+
if getattr(args, "super", False):
|
|
994
|
+
cfg.super_mode = True
|
|
995
|
+
if cfg.super_mode:
|
|
996
|
+
apply_super_mode(cfg)
|
|
997
|
+
elif args.interactive_ask:
|
|
982
998
|
cfg.interactive_permission_ask = True
|
|
983
999
|
else:
|
|
984
1000
|
if "GEMCODE_INTERACTIVE_PERMISSION_ASK" not in os.environ:
|
|
@@ -1023,6 +1039,11 @@ def main() -> None:
|
|
|
1023
1039
|
parser.add_argument("-C", "--directory", type=Path, default=Path.cwd(), help="Project root")
|
|
1024
1040
|
parser.add_argument("--session", default=None, help="Session id for SQLite-backed history")
|
|
1025
1041
|
parser.add_argument("--yes", action="store_true", help="Allow write_file / search_replace")
|
|
1042
|
+
parser.add_argument(
|
|
1043
|
+
"--super",
|
|
1044
|
+
action="store_true",
|
|
1045
|
+
help="Super mode: auto-approve all tool/shell use, skip HITL and AFC prompts (implies --yes).",
|
|
1046
|
+
)
|
|
1026
1047
|
parser.add_argument(
|
|
1027
1048
|
"--interactive-ask",
|
|
1028
1049
|
action="store_true",
|
|
@@ -1096,7 +1117,11 @@ def main() -> None:
|
|
|
1096
1117
|
if args.model_mode is None:
|
|
1097
1118
|
cfg.model_mode = "fast"
|
|
1098
1119
|
cfg.yes_to_all = args.yes
|
|
1099
|
-
if args.
|
|
1120
|
+
if args.super:
|
|
1121
|
+
cfg.super_mode = True
|
|
1122
|
+
if cfg.super_mode:
|
|
1123
|
+
apply_super_mode(cfg)
|
|
1124
|
+
elif args.interactive_ask:
|
|
1100
1125
|
cfg.interactive_permission_ask = True
|
|
1101
1126
|
else:
|
|
1102
1127
|
# If user didn't explicitly set env, default to HITL when we're in a TTY.
|
|
@@ -374,6 +374,13 @@ class GemCodeConfig:
|
|
|
374
374
|
default_factory=lambda: _truthy_env("GEMCODE_BACKGROUND_LEARNER", default=False)
|
|
375
375
|
)
|
|
376
376
|
|
|
377
|
+
# "Super" mode: fully autonomous session — auto-approve mutating/shell tools,
|
|
378
|
+
# skip interactive HITL and AFC tool-mode prompts, and prefer non-blocking UX.
|
|
379
|
+
# Enable with ``GEMCODE_SUPER_MODE=1`` or ``gemcode --super``.
|
|
380
|
+
super_mode: bool = field(
|
|
381
|
+
default_factory=lambda: _truthy_env("GEMCODE_SUPER_MODE", default=False)
|
|
382
|
+
)
|
|
383
|
+
|
|
377
384
|
def __post_init__(self) -> None:
|
|
378
385
|
self.project_root = self.project_root.resolve()
|
|
379
386
|
# Default agentic depth when env omits GEMCODE_MAX_LLM_CALLS (was: None → SDK default).
|
|
@@ -479,6 +486,24 @@ class GemCodeConfig:
|
|
|
479
486
|
"tar",
|
|
480
487
|
)
|
|
481
488
|
)
|
|
489
|
+
if self.super_mode:
|
|
490
|
+
apply_super_mode(self)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def apply_super_mode(cfg: GemCodeConfig) -> None:
|
|
494
|
+
"""
|
|
495
|
+
Apply super-mode policy: no interactive tool HITL, auto-approve GemCode gates,
|
|
496
|
+
keep all toolsets (skip AFC stdin prompt via ``_afc_choice``), relax strict
|
|
497
|
+
permission mode so shell tools can run.
|
|
498
|
+
"""
|
|
499
|
+
if not getattr(cfg, "super_mode", False):
|
|
500
|
+
return
|
|
501
|
+
cfg.yes_to_all = True
|
|
502
|
+
cfg.interactive_permission_ask = False
|
|
503
|
+
if getattr(cfg, "permission_mode", "") == "strict":
|
|
504
|
+
cfg.permission_mode = "default"
|
|
505
|
+
object.__setattr__(cfg, "_afc_choice", "all")
|
|
506
|
+
object.__setattr__(cfg, "_attachments_allowed", True)
|
|
482
507
|
|
|
483
508
|
|
|
484
509
|
def load_dotenv_optional() -> None:
|
|
@@ -18,11 +18,6 @@ from google.adk.runners import Runner
|
|
|
18
18
|
from google.genai import types
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
# Delays (seconds) between successive transient-error retries: 2s, 5s, 12s.
|
|
22
|
-
# Three retries = up to ~19 seconds of total wait before giving up.
|
|
23
|
-
_TRANSIENT_RETRY_DELAYS = [2.0, 5.0, 12.0]
|
|
24
|
-
|
|
25
|
-
|
|
26
21
|
_HITL_PROMPT_LOCK = Lock()
|
|
27
22
|
|
|
28
23
|
async def _maybe_enqueue_kaira_autopilot(*, cfg: "GemCodeConfig", session_id: str) -> None:
|
|
@@ -423,14 +418,14 @@ async def run_turn(
|
|
|
423
418
|
next_message=current_message, do_reset=do_reset
|
|
424
419
|
)
|
|
425
420
|
except Exception as _exc:
|
|
426
|
-
from gemcode.model_errors import is_transient_error
|
|
427
|
-
if is_transient_error(_exc) and transient_attempts < len(
|
|
428
|
-
delay =
|
|
421
|
+
from gemcode.model_errors import API_TRANSIENT_RETRY_DELAYS_SEC, is_transient_error
|
|
422
|
+
if is_transient_error(_exc) and transient_attempts < len(API_TRANSIENT_RETRY_DELAYS_SEC):
|
|
423
|
+
delay = API_TRANSIENT_RETRY_DELAYS_SEC[transient_attempts]
|
|
429
424
|
transient_attempts += 1
|
|
430
425
|
_tui_active = os.environ.get("GEMCODE_TUI_ACTIVE", "0").lower() in ("1", "true", "yes", "on")
|
|
431
426
|
_msg = (
|
|
432
427
|
f"\n[gemcode] Transient API error ({type(_exc).__name__}). "
|
|
433
|
-
f"Retrying in {delay:.0f}s (attempt {transient_attempts}/{len(
|
|
428
|
+
f"Retrying in {delay:.0f}s (attempt {transient_attempts}/{len(API_TRANSIENT_RETRY_DELAYS_SEC)})...\n"
|
|
434
429
|
)
|
|
435
430
|
print(_msg, file=sys.stderr)
|
|
436
431
|
# Surface retry notice in TUI if available.
|
|
@@ -460,11 +455,20 @@ async def run_turn(
|
|
|
460
455
|
and hasattr(sys.stdin, "isatty")
|
|
461
456
|
and sys.stdin.isatty()
|
|
462
457
|
)
|
|
458
|
+
auto_ok = bool(
|
|
459
|
+
cfg is not None
|
|
460
|
+
and (
|
|
461
|
+
bool(getattr(cfg, "yes_to_all", False))
|
|
462
|
+
or bool(getattr(cfg, "super_mode", False))
|
|
463
|
+
)
|
|
464
|
+
)
|
|
463
465
|
|
|
464
466
|
parts: list[types.Part] = []
|
|
465
467
|
for fc in confirmation_fcs:
|
|
466
468
|
tool_name, hint = _extract_hint_and_tool(fc)
|
|
467
|
-
if
|
|
469
|
+
if auto_ok:
|
|
470
|
+
ok = True
|
|
471
|
+
elif interactive_enabled:
|
|
468
472
|
suffix = f"\n Hint: {hint}" if hint else ""
|
|
469
473
|
ok = _prompt_yes_no(
|
|
470
474
|
f"\n[gemcode HITL] Approve tool call '{tool_name}'? [y/N]{suffix}\n> "
|
|
@@ -491,8 +491,12 @@ class KairaDaemon:
|
|
|
491
491
|
parts: list[types.Part] = []
|
|
492
492
|
for fc in confirmation_fcs:
|
|
493
493
|
tool_name, hint = _extract_hint_and_tool(fc)
|
|
494
|
-
|
|
495
|
-
|
|
494
|
+
auto_ok = bool(
|
|
495
|
+
getattr(self.cfg, "yes_to_all", False)
|
|
496
|
+
or getattr(self.cfg, "super_mode", False)
|
|
497
|
+
)
|
|
498
|
+
ok = bool(auto_ok)
|
|
499
|
+
if not ok and self._ipc is not None:
|
|
496
500
|
try:
|
|
497
501
|
ok = await self._ipc.request_confirmation(
|
|
498
502
|
job_id=job.job_id,
|
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
|
+
# Seconds between retries for transient API failures (shared by invoke.py and TUI).
|
|
8
|
+
API_TRANSIENT_RETRY_DELAYS_SEC: tuple[float, ...] = (2.0, 5.0, 12.0)
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
def is_transient_error(error: Exception) -> bool:
|
|
9
12
|
"""Return True for HTTP 503 / 429 and similar transient API errors that are safe to retry.
|
|
@@ -29,6 +32,21 @@ def is_transient_error(error: Exception) -> bool:
|
|
|
29
32
|
return True
|
|
30
33
|
|
|
31
34
|
msg = str(error)
|
|
35
|
+
ml = msg.lower()
|
|
36
|
+
|
|
37
|
+
# httpx / google-genai often raise ``ServerError`` for HTTP 500 without ``APIError.code``.
|
|
38
|
+
if et == "ServerError" or "ServerError" in et:
|
|
39
|
+
if any(code in msg for code in ("500", "502", "503", "504")):
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
# Gemini REST body shape: ``'code': 500`` / ``"INTERNAL"`` / "Internal error encountered."
|
|
43
|
+
if ("'code': 500" in msg or '"code": 500' in msg or re.search(r"\b500\b", msg)) and any(
|
|
44
|
+
p in ml for p in ("internal", "unavailable", "try again", "deadline", "timeout", "backend")
|
|
45
|
+
):
|
|
46
|
+
return True
|
|
47
|
+
if "internal error encountered" in ml:
|
|
48
|
+
return True
|
|
49
|
+
|
|
32
50
|
# Match the specific phrases Gemini uses in 503 responses
|
|
33
51
|
if "503" in msg and any(p in msg for p in ("high demand", "service unavailable", "overloaded")):
|
|
34
52
|
return True
|
|
@@ -257,6 +257,7 @@ SLASH_COMMANDS: list[tuple[str, str]] = [
|
|
|
257
257
|
("skills", "List GemSkills"),
|
|
258
258
|
("status", "Model, capabilities, thinking, limits"),
|
|
259
259
|
("style", "Output styles · /style <name>|off"),
|
|
260
|
+
("super", "Super mode · auto-approve tools/shell, no HITL · /super off"),
|
|
260
261
|
("summarise", "Summarise current session, persist key points, then reset · /summarize same"),
|
|
261
262
|
("thinking", "Thinking verbose/brief/off, budget, level"),
|
|
262
263
|
("tools", "Tool inventory · /tools smoke"),
|
|
@@ -334,6 +335,7 @@ def slash_help_lines() -> list[str]:
|
|
|
334
335
|
" Aliases: /image /img /file",
|
|
335
336
|
" /trust Show workspace trust status (file/shell tools)",
|
|
336
337
|
" /trust on|off Trust or revoke trust for this project root (~/.gemcode/trust.json)",
|
|
338
|
+
" /super Fully autonomous session (auto-approve tools; no HITL). /super off to disable flag only",
|
|
337
339
|
" /init Analyze project structure and generate GEMINI.md",
|
|
338
340
|
" /init force Regenerate GEMINI.md even if it already exists",
|
|
339
341
|
" /cost Show token usage and estimated cost for this session",
|
|
@@ -616,6 +616,23 @@ async def process_repl_slash(
|
|
|
616
616
|
out()
|
|
617
617
|
return ReplSlashResult(skip_model_turn=True)
|
|
618
618
|
|
|
619
|
+
# ── /super (fully autonomous: no HITL, auto-approve tools) ─────────────────
|
|
620
|
+
if name == "super":
|
|
621
|
+
from gemcode.config import apply_super_mode
|
|
622
|
+
|
|
623
|
+
args_s = (sc.args or "").strip().lower()
|
|
624
|
+
if args_s in ("off", "0", "false", "no"):
|
|
625
|
+
cfg.super_mode = False
|
|
626
|
+
out("Super mode: off (yes_to_all unchanged; restart or adjust flags to change approvals).")
|
|
627
|
+
out()
|
|
628
|
+
return ReplSlashResult(skip_model_turn=True)
|
|
629
|
+
cfg.super_mode = True
|
|
630
|
+
apply_super_mode(cfg)
|
|
631
|
+
out("Super mode: on — mutating/shell tools and ADK confirmations auto-approved; no AFC stdin prompt.")
|
|
632
|
+
out("Equivalent: gemcode --super or GEMCODE_SUPER_MODE=1")
|
|
633
|
+
out()
|
|
634
|
+
return ReplSlashResult(skip_model_turn=True)
|
|
635
|
+
|
|
619
636
|
# ── /add-dir (safe multi-root access) ──────────────────────────────────────
|
|
620
637
|
if name in ("add-dir", "add_dir", "adddir"):
|
|
621
638
|
args = (sc.args or "").strip()
|
|
@@ -55,6 +55,14 @@ def build_tool_manifest(cfg: GemCodeConfig) -> str | None:
|
|
|
55
55
|
yes_to_all = bool(getattr(cfg, "yes_to_all", False))
|
|
56
56
|
interactive_ask_on = bool(getattr(cfg, "interactive_permission_ask", False))
|
|
57
57
|
sticky_hitl = bool(getattr(cfg, "interactive_hitl_sticky_session", True))
|
|
58
|
+
super_on = bool(getattr(cfg, "super_mode", False))
|
|
59
|
+
guc_manifest = (
|
|
60
|
+
"- **`get_user_choice(options)`** — (super mode) returns the **first** option immediately with no user prompt. "
|
|
61
|
+
"Put the preferred default first."
|
|
62
|
+
if super_on
|
|
63
|
+
else "- **`get_user_choice(options)`** — present the user with a structured list of options (2–6 items). "
|
|
64
|
+
"Returns the user's selected option. Use instead of open-ended questions when responses are bounded."
|
|
65
|
+
)
|
|
58
66
|
|
|
59
67
|
# Core custom tools.
|
|
60
68
|
read_only = sorted(READ_ONLY_TOOLS)
|
|
@@ -97,6 +105,30 @@ def build_tool_manifest(cfg: GemCodeConfig) -> str | None:
|
|
|
97
105
|
|
|
98
106
|
memory_on = bool(getattr(cfg, "enable_memory", False))
|
|
99
107
|
|
|
108
|
+
mm = (getattr(cfg, "model_mode", "") or "").strip().lower()
|
|
109
|
+
cm = (getattr(cfg, "capability_mode", "") or "").strip().lower()
|
|
110
|
+
auto_routing_note = ""
|
|
111
|
+
if mm == "auto" or cm == "auto":
|
|
112
|
+
auto_routing_note = (
|
|
113
|
+
f"\n- **Dynamic routing:** `model_mode={mm}`, `capability_mode={cm}` — per-turn defaults are **hints**; "
|
|
114
|
+
"still pick the smallest depth/toolset that fits the ask.\n"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
calibration_manifest = f"""### Calibration (aligned with main instruction)
|
|
118
|
+
- **Repo vs external:** ground claims about *this repo* with reads/grep/tests; use research/web for **external** docs, APIs, or facts outside the tree.
|
|
119
|
+
- **Orchestration:** use `run_subtask` / `spawn_subtasks` only for **parallel independent** work or explicit verification; merge into **one** answer; skip fan-out for trivial linear tasks.
|
|
120
|
+
- **Finish line:** verify risky edits (test/lint/read-back) before declaring done.{auto_routing_note}"""
|
|
121
|
+
|
|
122
|
+
_disc = os.environ.get("GEMCODE_ENGINEERING_DISCIPLINE", "1").strip().lower()
|
|
123
|
+
discipline_manifest = ""
|
|
124
|
+
if _disc not in ("0", "false", "no", "off"):
|
|
125
|
+
discipline_manifest = """
|
|
126
|
+
|
|
127
|
+
### Engineering discipline (aligned with main instruction)
|
|
128
|
+
- **Ambiguity:** state what you understood or ask **one** precise question; prefer repo evidence over guesses.
|
|
129
|
+
- **Scope:** deliver the ask with the **smallest** adequate change; skip speculative extras.
|
|
130
|
+
- **Surgical:** touch only what you must; match local style; clean up orphans **your** edit introduced."""
|
|
131
|
+
|
|
100
132
|
manifest = f"""## Tool system (GemCode)
|
|
101
133
|
|
|
102
134
|
### Execution model
|
|
@@ -104,6 +136,8 @@ def build_tool_manifest(cfg: GemCodeConfig) -> str | None:
|
|
|
104
136
|
- **Reason end-to-end autonomously.** The user expects complete tasks, not a questionnaire. Use `think` before complex actions, `todo_write` to track multi-step work.
|
|
105
137
|
- **Never stop after the first tool call succeeds.** Keep going until the full task is done or you hit a genuine blocker.
|
|
106
138
|
|
|
139
|
+
{calibration_manifest}{discipline_manifest}
|
|
140
|
+
|
|
107
141
|
### Permission policy
|
|
108
142
|
| Setting | Value |
|
|
109
143
|
|---------|-------|
|
|
@@ -126,7 +160,7 @@ def build_tool_manifest(cfg: GemCodeConfig) -> str | None:
|
|
|
126
160
|
- Returns the sub-agent's final text as `result`.
|
|
127
161
|
- Use for: context-heavy exploration (reading 50+ files), parallel investigation of independent subsystems, verification passes after you finish work.
|
|
128
162
|
- Always give the sub-agent enough context to work independently; end the task with "Summarise your findings clearly."
|
|
129
|
-
|
|
163
|
+
{guc_manifest}
|
|
130
164
|
- **`load_artifacts(filenames)`** — load one or more named artifacts (binary/large files) saved in this or a previous session. Returns the content of each. Use `user:filename` prefix for cross-session artifacts.
|
|
131
165
|
- **`exit_loop()`** — signal the surrounding LoopAgent to stop iterating and emit the final result. Only relevant when running inside a LoopAgent pipeline (e.g. the `/refine` write→test→fix loop).
|
|
132
166
|
|
|
@@ -38,7 +38,9 @@ SHELL_TOOLS: frozenset[str] = frozenset({"run_command", "bash"})
|
|
|
38
38
|
# Session planning only (no disk / shell; no extra permission)
|
|
39
39
|
# think — in-context reasoning scratchpad (no-op, no side effects)
|
|
40
40
|
# run_subtask — spawns a sub-agent; inherits parent permission settings
|
|
41
|
-
PLANNING_TOOLS: frozenset[str] = frozenset(
|
|
41
|
+
PLANNING_TOOLS: frozenset[str] = frozenset(
|
|
42
|
+
{"todo_write", "think", "run_subtask", "spawn_subtasks"}
|
|
43
|
+
)
|
|
42
44
|
|
|
43
45
|
ToolConcurrency = Literal["parallel_safe", "serial_mutating", "shell"]
|
|
44
46
|
|
|
@@ -43,8 +43,9 @@ def _build_sub_tools(cfg: GemCodeConfig) -> list:
|
|
|
43
43
|
|
|
44
44
|
# ADK special interactive tools — always try to include.
|
|
45
45
|
try:
|
|
46
|
-
from
|
|
47
|
-
|
|
46
|
+
from gemcode.tools.user_choice import append_user_choice_load_artifacts_exit_loop
|
|
47
|
+
|
|
48
|
+
append_user_choice_load_artifacts_exit_loop(cfg, tools)
|
|
48
49
|
except Exception:
|
|
49
50
|
pass
|
|
50
51
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""User-choice tool: interactive (ADK) vs automatic (super mode)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from gemcode.config import GemCodeConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def make_super_get_user_choice_tool(cfg: GemCodeConfig):
|
|
12
|
+
"""
|
|
13
|
+
Non-interactive stand-in for ADK ``get_user_choice`` when ``cfg.super_mode``.
|
|
14
|
+
|
|
15
|
+
ADK's built-in tool is a LongRunningFunctionTool that returns ``None`` and
|
|
16
|
+
waits for UI; in super mode we return the first non-empty option immediately.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def get_user_choice(options: list[str], tool_context: Any) -> str | None:
|
|
20
|
+
"""Pick the first option without blocking on human input (super mode)."""
|
|
21
|
+
try:
|
|
22
|
+
tool_context.actions.skip_summarization = True
|
|
23
|
+
except Exception:
|
|
24
|
+
pass
|
|
25
|
+
for opt in options or []:
|
|
26
|
+
s = str(opt).strip()
|
|
27
|
+
if s:
|
|
28
|
+
return s
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
get_user_choice.__name__ = "get_user_choice"
|
|
32
|
+
return get_user_choice
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def append_user_choice_load_artifacts_exit_loop(
|
|
36
|
+
cfg: GemCodeConfig, tools: list,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Append ``get_user_choice``, ``load_artifacts``, ``exit_loop`` like ADK defaults.
|
|
40
|
+
|
|
41
|
+
When ``cfg.super_mode``, ``get_user_choice`` is a plain function that auto-picks
|
|
42
|
+
the first option; otherwise the ADK LongRunningFunctionTool is used.
|
|
43
|
+
"""
|
|
44
|
+
if getattr(cfg, "super_mode", False):
|
|
45
|
+
tools.append(make_super_get_user_choice_tool(cfg))
|
|
46
|
+
else:
|
|
47
|
+
try:
|
|
48
|
+
from google.adk.tools import get_user_choice as adk_get_user_choice
|
|
49
|
+
|
|
50
|
+
tools.append(adk_get_user_choice)
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
try:
|
|
54
|
+
from google.adk.tools import exit_loop, load_artifacts
|
|
55
|
+
|
|
56
|
+
tools.extend([load_artifacts, exit_loop])
|
|
57
|
+
except Exception:
|
|
58
|
+
pass
|