gemcode 0.3.22__py3-none-any.whl → 0.3.23__py3-none-any.whl

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/config.py CHANGED
@@ -244,6 +244,13 @@ class GemCodeConfig:
244
244
  default_factory=lambda: _opt_int("GEMCODE_THINKING_BUDGET")
245
245
  )
246
246
 
247
+ # Controls how the TUI renders model thinking: True = full Rich Markdown,
248
+ # False = collapsed one-line excerpt (default, like OpenClaude).
249
+ # Toggled at runtime via /thinking verbose|brief.
250
+ show_full_thinking: bool = field(
251
+ default_factory=lambda: _truthy_env("GEMCODE_SHOW_FULL_THINKING", default=False)
252
+ )
253
+
247
254
  def __post_init__(self) -> None:
248
255
  self.project_root = self.project_root.resolve()
249
256
  # Default agentic depth when env omits GEMCODE_MAX_LLM_CALLS (was: None → SDK default).
gemcode/repl_commands.py CHANGED
@@ -162,9 +162,11 @@ def slash_help_lines() -> list[str]:
162
162
  "Slash commands:",
163
163
  " (CLI) gemcode -C DIR Use a project folder as root (recommended vs. ~ )",
164
164
  " (CLI) gemcode login Save or change API key (~/.gemcode/credentials.json)",
165
+ "",
166
+ " Session:",
165
167
  " /help Show this help",
166
- " /status Show current session/model info",
167
- " /config Show key GemCode env/config toggles",
168
+ " /status Full status: model, capabilities, thinking, limits",
169
+ " /config All active config fields (model, caps, context, thinking)",
168
170
  " /session Print current session id",
169
171
  " /session new Start a new session id (history reset)",
170
172
  " /clear Alias for /session new",
@@ -173,9 +175,26 @@ def slash_help_lines() -> list[str]:
173
175
  " /audit [N] Tail of .gemcode/audit.log (default 40 lines)",
174
176
  " /tools List tool inventory for this config",
175
177
  " /doctor Environment sanity check",
178
+ " /version Print GemCode version hint",
179
+ " /exit Exit the REPL",
180
+ "",
181
+ " Model:",
176
182
  " /model Show model routing info",
177
183
  " /model use <id> Override model for this REPL session",
178
- " /model list List available Gemini model IDs",
184
+ " /model list List available Gemini model IDs",
185
+ " /mode Show current model_mode",
186
+ " /mode <fast|balanced|quality|auto> Set model selection strategy",
187
+ "",
188
+ " Capabilities (all require runner rebuild — shown automatically):",
189
+ " /research Show deep-research status",
190
+ " /research on|off Enable/disable Google Search + URL Context tools",
191
+ " /embeddings on|off Enable/disable semantic file search (Embeddings API)",
192
+ " /caps View all capability flags",
193
+ " /caps <research|embeddings|all|reset> Bulk capability control",
194
+ " /memory Show persistent memory status",
195
+ " /memory on|off Enable/disable session memory",
196
+ "",
197
+ " Thinking:",
179
198
  " /thinking Show current thinking config",
180
199
  " /thinking verbose Show full thinking text each turn",
181
200
  " /thinking brief Show collapsed one-line excerpt (default)",
@@ -183,9 +202,14 @@ def slash_help_lines() -> list[str]:
183
202
  " /thinking on Re-enable thinking (auto budget/level)",
184
203
  " /thinking budget <N> Set thinking token budget (Gemini 2.5, 0=off, -1=dynamic)",
185
204
  " /thinking level <L> Set thinking level: minimal|low|medium|high (Gemini 3.x)",
205
+ "",
206
+ " Limits:",
207
+ " /limits Show all execution limits",
208
+ " /limits calls <N> Set max LLM calls per turn",
209
+ " /budget Show per-turn token budget",
210
+ " /budget <N>|off Set or clear per-turn token budget",
211
+ "",
212
+ " Other:",
186
213
  " /permissions Show permission / HITL settings",
187
- " /memory Show persistent memory settings",
188
214
  " /hooks Show post-turn hook configuration",
189
- " /version Print GemCode version hint",
190
- " /exit Exit the REPL",
191
215
  ]
gemcode/repl_slash.py CHANGED
@@ -181,29 +181,73 @@ async def process_repl_slash(
181
181
  return ReplSlashResult(skip_model_turn=True)
182
182
 
183
183
  if name == "status":
184
- out(f"model: {cfg.model}")
185
- out(f"project_root: {cfg.project_root}")
186
- out(f"session_id: {session_id}")
187
- out(f"permission_mode: {cfg.permission_mode}")
188
- out(f"yes_to_all: {cfg.yes_to_all}")
184
+ out(f"model: {cfg.model}")
185
+ out(f"model_mode: {cfg.model_mode}")
186
+ out(f"session_id: {session_id}")
187
+ out(f"project_root: {cfg.project_root}")
188
+ out()
189
+ out("Capabilities:")
190
+ out(f" deep_research: {'on ✓' if cfg.enable_deep_research else 'off'}")
191
+ out(f" embeddings: {'on ✓' if cfg.enable_embeddings else 'off'}")
192
+ out(f" memory: {'on ✓' if cfg.enable_memory else 'off'}")
193
+ out(f" computer_use: {'on ✓' if cfg.enable_computer_use else 'off'}")
194
+ out(f" maps_grounding: {'on ✓' if cfg.enable_maps_grounding else 'off'}")
195
+ out(f" auto_routing: {cfg.capability_mode}")
196
+ out()
197
+ out("Thinking:")
198
+ out(f" disabled: {cfg.disable_thinking}")
199
+ if cfg.thinking_level:
200
+ out(f" level: {cfg.thinking_level}")
201
+ if cfg.thinking_budget is not None:
202
+ out(f" budget: {cfg.thinking_budget:,} tokens")
203
+ out(f" display: {'verbose (full)' if cfg.show_full_thinking else 'brief (collapsed)'}")
204
+ out()
205
+ out("Permissions / limits:")
206
+ out(f" permission_mode: {cfg.permission_mode}")
207
+ out(f" yes_to_all: {cfg.yes_to_all}")
208
+ out(f" max_llm_calls: {cfg.max_llm_calls or '(SDK default)'}")
209
+ out(f" token_budget: {f'{cfg.token_budget:,}' if cfg.token_budget else '(none)'}")
189
210
  out()
190
211
  return ReplSlashResult(skip_model_turn=True)
191
212
 
192
213
  if name == "config":
193
- out("Key settings (env vars):")
194
- out(f" GEMCODE_MODEL={os.environ.get('GEMCODE_MODEL', cfg.model)}")
195
- out(
196
- f" GEMCODE_TOOL_RESULT_MAX_CHARS={os.environ.get('GEMCODE_TOOL_RESULT_MAX_CHARS', '12000')}"
197
- )
198
- out(f" GEMCODE_MAX_CONTEXT_CHARS={os.environ.get('GEMCODE_MAX_CONTEXT_CHARS', '400000')}")
199
- out(f" GEMCODE_CONTEXT_SHRINK={os.environ.get('GEMCODE_CONTEXT_SHRINK', '1')}")
200
- out(f" GEMCODE_AUTOCOMPACT={os.environ.get('GEMCODE_AUTOCOMPACT', '1')}")
201
- out(
202
- f" GEMCODE_AUTOCOMPACT_KEEP_CONTENT_ITEMS={os.environ.get('GEMCODE_AUTOCOMPACT_KEEP_CONTENT_ITEMS', '18')}"
203
- )
204
- out(
205
- f" GEMCODE_AUTOCOMPACT_BUFFER_CHARS={os.environ.get('GEMCODE_AUTOCOMPACT_BUFFER_CHARS', '60000')}"
206
- )
214
+ out("Active configuration:")
215
+ out()
216
+ out(" Model:")
217
+ out(f" model: {cfg.model}")
218
+ out(f" model_mode: {cfg.model_mode} (fast|balanced|quality|auto — /mode)")
219
+ out(f" model_family_mode: {cfg.model_family_mode}")
220
+ out(f" model_overridden: {cfg.model_overridden}")
221
+ out(f" model_deep_research: {cfg.model_deep_research}")
222
+ out()
223
+ out(" Capabilities (/research, /embeddings, /caps, /memory):")
224
+ out(f" enable_deep_research: {cfg.enable_deep_research}")
225
+ out(f" enable_embeddings: {cfg.enable_embeddings}")
226
+ out(f" enable_memory: {cfg.enable_memory}")
227
+ out(f" enable_computer_use: {cfg.enable_computer_use}")
228
+ out(f" enable_maps_grounding: {cfg.enable_maps_grounding}")
229
+ out(f" capability_mode: {cfg.capability_mode} (auto-routing)")
230
+ out(f" tool_combination_mode: {cfg.tool_combination_mode}")
231
+ out()
232
+ out(" Context / limits (/limits, /budget):")
233
+ out(f" max_llm_calls: {cfg.max_llm_calls or '(SDK default)'}")
234
+ out(f" max_context_chars: {cfg.max_context_chars:,}")
235
+ out(f" tool_result_max_chars: {cfg.tool_result_max_chars:,}")
236
+ out(f" max_content_items: {cfg.max_content_items}")
237
+ out(f" context_shrink: {cfg.context_shrink_enabled}")
238
+ out(f" token_budget: {f'{cfg.token_budget:,}' if cfg.token_budget else '(none)'}")
239
+ out(f" max_session_tokens: {f'{cfg.max_session_tokens:,}' if cfg.max_session_tokens else '(none)'}")
240
+ out()
241
+ out(" Thinking (/thinking):")
242
+ out(f" disable_thinking: {cfg.disable_thinking}")
243
+ out(f" thinking_level: {cfg.thinking_level or '(auto)'}")
244
+ out(f" thinking_budget: {cfg.thinking_budget if cfg.thinking_budget is not None else '(auto)'}")
245
+ out(f" show_full_thinking: {cfg.show_full_thinking}")
246
+ out()
247
+ out(" Autocompact:")
248
+ out(f" GEMCODE_AUTOCOMPACT: {os.environ.get('GEMCODE_AUTOCOMPACT', '1')}")
249
+ out(f" GEMCODE_AUTOCOMPACT_BUFFER_CHARS: {os.environ.get('GEMCODE_AUTOCOMPACT_BUFFER_CHARS', '60000')}")
250
+ out(f" GEMCODE_AUTOCOMPACT_KEEP_CONTENT_ITEMS: {os.environ.get('GEMCODE_AUTOCOMPACT_KEEP_CONTENT_ITEMS', '18')}")
207
251
  out()
208
252
  return ReplSlashResult(skip_model_turn=True)
209
253
 
@@ -271,6 +315,203 @@ async def process_repl_slash(
271
315
  if name in ("exit", "quit"):
272
316
  return ReplSlashResult(exit_repl=True)
273
317
 
318
+ # ── /research ────────────────────────────────────────────────────────────
319
+ if name == "research":
320
+ args_s = (sc.args or "").strip().lower()
321
+ if not args_s or args_s in ("status", "show"):
322
+ status = "on ✓" if cfg.enable_deep_research else "off"
323
+ out(f"deep_research: {status}")
324
+ if cfg.enable_deep_research:
325
+ out(f" model_deep_research: {cfg.model_deep_research}")
326
+ out(f" enable_maps_grounding:{cfg.enable_maps_grounding}")
327
+ out(" tools: google_search, url_context")
328
+ out()
329
+ out("Commands: /research on · /research off")
330
+ out("When on: Google Search + URL Context are injected as tools.")
331
+ out(" Model switches to the deep-research routing model.")
332
+ out()
333
+ return ReplSlashResult(skip_model_turn=True)
334
+ if args_s == "on":
335
+ cfg.enable_deep_research = True
336
+ out("research: on — Google Search + URL Context enabled")
337
+ out(" Runner will rebuild on next turn to inject the new tools.")
338
+ out()
339
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
340
+ if args_s == "off":
341
+ cfg.enable_deep_research = False
342
+ out("research: off")
343
+ out()
344
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
345
+ out(f"Unknown /research subcommand: '{args_s}'")
346
+ out("Usage: /research [on|off]")
347
+ out()
348
+ return ReplSlashResult(skip_model_turn=True)
349
+
350
+ # ── /embeddings ──────────────────────────────────────────────────────────
351
+ if name in ("embeddings", "embed"):
352
+ args_s = (sc.args or "").strip().lower()
353
+ if not args_s or args_s in ("status", "show"):
354
+ status = "on ✓" if cfg.enable_embeddings else "off"
355
+ out(f"embeddings: {status}")
356
+ if cfg.enable_embeddings:
357
+ out(f" embeddings_model: {cfg.embeddings_model}")
358
+ out(" tools: semantic_search_files")
359
+ out()
360
+ out("Commands: /embeddings on · /embeddings off")
361
+ out("When on: semantic (meaning-based) file search via Google Embeddings API.")
362
+ out()
363
+ return ReplSlashResult(skip_model_turn=True)
364
+ if args_s == "on":
365
+ cfg.enable_embeddings = True
366
+ out("embeddings: on — semantic_search_files tool injected")
367
+ out(" Runner will rebuild on next turn.")
368
+ out()
369
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
370
+ if args_s == "off":
371
+ cfg.enable_embeddings = False
372
+ out("embeddings: off")
373
+ out()
374
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
375
+ out(f"Unknown /embeddings subcommand: '{args_s}'")
376
+ out("Usage: /embeddings [on|off]")
377
+ out()
378
+ return ReplSlashResult(skip_model_turn=True)
379
+
380
+ # ── /mode ─────────────────────────────────────────────────────────────────
381
+ if name == "mode":
382
+ args_s = (sc.args or "").strip().lower()
383
+ valid_modes = ("fast", "balanced", "quality", "auto")
384
+ if not args_s:
385
+ out(f"model_mode: {cfg.model_mode}")
386
+ out()
387
+ out(" fast — use the fastest model for edits and tool-heavy tasks")
388
+ out(" balanced — moderate speed/quality (default)")
389
+ out(" quality — highest-quality model for architecture and complex reasoning")
390
+ out(" auto — GemCode picks based on prompt complexity each turn")
391
+ out()
392
+ out("Usage: /mode <fast|balanced|quality|auto>")
393
+ out()
394
+ return ReplSlashResult(skip_model_turn=True)
395
+ if args_s in valid_modes:
396
+ cfg.model_mode = args_s
397
+ # Clear model_overridden so the new mode takes effect through routing
398
+ if not getattr(cfg, "_model_explicitly_set", False):
399
+ cfg.model_overridden = False
400
+ out(f"model_mode: {args_s}")
401
+ out()
402
+ return ReplSlashResult(skip_model_turn=True)
403
+ out(f"Unknown mode '{args_s}'. Choose from: {', '.join(valid_modes)}")
404
+ out()
405
+ return ReplSlashResult(skip_model_turn=True)
406
+
407
+ # ── /budget ───────────────────────────────────────────────────────────────
408
+ if name in ("budget", "token-budget"):
409
+ args_s = (sc.args or "").strip().lower()
410
+ if not args_s:
411
+ tb = cfg.token_budget
412
+ out(f"token_budget: {f'{tb:,} tokens/turn' if tb is not None else '(none — unlimited)'}")
413
+ out()
414
+ out("Usage: /budget <N> Set per-turn token budget (e.g. /budget 50000)")
415
+ out(" /budget off Remove budget limit")
416
+ out()
417
+ return ReplSlashResult(skip_model_turn=True)
418
+ if args_s == "off":
419
+ cfg.token_budget = None
420
+ out("token_budget: (none — unlimited)")
421
+ out()
422
+ return ReplSlashResult(skip_model_turn=True)
423
+ try:
424
+ n = int(args_s)
425
+ if n <= 0:
426
+ out("Token budget must be a positive integer (or 'off').")
427
+ out()
428
+ return ReplSlashResult(skip_model_turn=True)
429
+ cfg.token_budget = n
430
+ out(f"token_budget: {n:,} tokens per turn")
431
+ out()
432
+ return ReplSlashResult(skip_model_turn=True)
433
+ except ValueError:
434
+ out(f"Invalid budget '{args_s}' — use a number or 'off'.")
435
+ out()
436
+ return ReplSlashResult(skip_model_turn=True)
437
+
438
+ # ── /caps ─────────────────────────────────────────────────────────────────
439
+ if name in ("caps", "capabilities", "capability"):
440
+ args_s = (sc.args or "").strip().lower()
441
+ valid_caps = ("auto", "research", "embeddings", "computer", "all", "none", "reset")
442
+ out("Active capabilities:")
443
+ out(f" deep_research: {'on' if cfg.enable_deep_research else 'off'}")
444
+ out(f" embeddings: {'on' if cfg.enable_embeddings else 'off'}")
445
+ out(f" memory: {'on' if cfg.enable_memory else 'off'}")
446
+ out(f" computer_use: {'on' if cfg.enable_computer_use else 'off'}")
447
+ out(f" maps_grounding: {'on' if cfg.enable_maps_grounding else 'off'}")
448
+ out(f" capability_mode (auto-routing): {cfg.capability_mode}")
449
+ out()
450
+ if not args_s:
451
+ out("Commands:")
452
+ out(" /caps none — turn all off, capability_mode=auto")
453
+ out(" /caps research — enable_deep_research on")
454
+ out(" /caps embeddings — enable_embeddings on")
455
+ out(" /caps all — all modalities on")
456
+ out(" /caps reset — reset to startup defaults (all off, auto mode)")
457
+ out()
458
+ return ReplSlashResult(skip_model_turn=True)
459
+ if args_s in ("none", "reset"):
460
+ cfg.enable_deep_research = False
461
+ cfg.enable_embeddings = False
462
+ cfg.enable_computer_use = False
463
+ cfg.enable_maps_grounding = False
464
+ cfg.capability_mode = "auto"
465
+ out("capabilities: reset to defaults (all off, auto mode)")
466
+ out()
467
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
468
+ if args_s == "research":
469
+ cfg.enable_deep_research = True
470
+ out("enable_deep_research: on (runner rebuilding…)")
471
+ out()
472
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
473
+ if args_s == "embeddings":
474
+ cfg.enable_embeddings = True
475
+ out("enable_embeddings: on (runner rebuilding…)")
476
+ out()
477
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
478
+ if args_s == "all":
479
+ cfg.enable_deep_research = True
480
+ cfg.enable_embeddings = True
481
+ cfg.enable_computer_use = True
482
+ out("capabilities: all on (runner rebuilding…)")
483
+ out()
484
+ return ReplSlashResult(skip_model_turn=True, force_rebuild_runner=True)
485
+ out(f"Unknown /caps value '{args_s}'. Choose from: {', '.join(valid_caps)}")
486
+ out()
487
+ return ReplSlashResult(skip_model_turn=True)
488
+
489
+ # ── /limits ───────────────────────────────────────────────────────────────
490
+ if name == "limits":
491
+ args_s = (sc.args or "").strip()
492
+ out("Current limits:")
493
+ out(f" max_llm_calls: {cfg.max_llm_calls or '(SDK default)'}")
494
+ out(f" max_context_chars: {cfg.max_context_chars:,}")
495
+ out(f" tool_result_max_chars: {cfg.tool_result_max_chars:,}")
496
+ out(f" max_content_items: {cfg.max_content_items}")
497
+ out(f" context_shrink: {cfg.context_shrink_enabled}")
498
+ out(f" token_budget: {f'{cfg.token_budget:,}' if cfg.token_budget else '(none)'}")
499
+ out(f" max_session_tokens: {f'{cfg.max_session_tokens:,}' if cfg.max_session_tokens else '(none)'}")
500
+ out()
501
+ if args_s:
502
+ parts = args_s.split()
503
+ if parts[0] == "calls" and len(parts) >= 2:
504
+ try:
505
+ n = int(parts[1])
506
+ if n > 0:
507
+ cfg.max_llm_calls = n
508
+ out(f"max_llm_calls: {n}")
509
+ out()
510
+ except ValueError:
511
+ out(f"Invalid value '{parts[1]}'")
512
+ out()
513
+ return ReplSlashResult(skip_model_turn=True)
514
+
274
515
  if name == "thinking":
275
516
  model_id = getattr(cfg, "model", "") or ""
276
517
  is_25 = "2.5" in model_id
@@ -278,10 +519,10 @@ async def process_repl_slash(
278
519
 
279
520
  if not args:
280
521
  # Show current thinking config.
281
- disable = bool(getattr(cfg, "disable_thinking", False))
282
- level = getattr(cfg, "thinking_level", None)
283
- budget = getattr(cfg, "thinking_budget", None)
284
- verbose = bool(getattr(cfg, "show_full_thinking", False))
522
+ disable = bool(cfg.disable_thinking)
523
+ level = cfg.thinking_level
524
+ budget = cfg.thinking_budget
525
+ verbose = bool(cfg.show_full_thinking)
285
526
  out("Thinking config:")
286
527
  out(f" model: {model_id or '(default)'}")
287
528
  out(f" disable_thinking: {disable}")
@@ -310,13 +551,13 @@ async def process_repl_slash(
310
551
  sub = parts[0].lower()
311
552
 
312
553
  if sub in ("verbose", "full"):
313
- setattr(cfg, "show_full_thinking", True)
554
+ cfg.show_full_thinking = True
314
555
  out("thinking display: verbose — full thinking shown each turn")
315
556
  out()
316
557
  return ReplSlashResult(skip_model_turn=True)
317
558
 
318
559
  if sub in ("brief", "short", "collapsed"):
319
- setattr(cfg, "show_full_thinking", False)
560
+ cfg.show_full_thinking = False
320
561
  out("thinking display: brief — collapsed one-line excerpt (default)")
321
562
  out()
322
563
  return ReplSlashResult(skip_model_turn=True)
@@ -43,16 +43,22 @@ SLASH_COMMANDS: list[tuple[str, str]] = [
43
43
  ("help", "List all available commands"),
44
44
  ("clear", "Start a fresh session (clears history) · alias: /session new"),
45
45
  ("model", "View or switch model · /model use <id> · /model list"),
46
+ ("mode", "Set model mode · /mode fast|balanced|quality|auto"),
46
47
  ("thinking", "Thinking config · /thinking verbose · /thinking brief · /thinking budget <N>"),
47
- ("status", "Show session ID, model, and current settings"),
48
+ ("status", "Show full session status: model, capabilities, thinking, limits"),
48
49
  ("context", "Show context window usage and token counts"),
49
50
  ("compact", "Summarise conversation history to reclaim context space"),
51
+ ("research", "Toggle Google Search + URL Context · /research on|off"),
52
+ ("embeddings", "Toggle semantic file search via Embeddings API · /embeddings on|off"),
53
+ ("caps", "View/toggle all capabilities · /caps · /caps all · /caps reset"),
54
+ ("memory", "Toggle persistent memory · /memory on|off"),
55
+ ("budget", "Set per-turn token budget · /budget <N> · /budget off"),
56
+ ("limits", "Show/set execution limits (max_llm_calls, context, etc.)"),
50
57
  ("tools", "List all tools and their permission categories"),
51
- ("config", "Show active configuration and environment variables"),
58
+ ("config", "Show full active configuration (all fields)"),
52
59
  ("permissions", "Show current permission mode (default / strict / yes)"),
53
60
  ("session", "Show current session ID · /session new to reset"),
54
61
  ("audit", "Show recent audit log · /audit [N lines]"),
55
- ("memory", "Show memory / storage settings"),
56
62
  ("doctor", "Run diagnostics and validate the environment"),
57
63
  ("hooks", "Show post-turn hook configuration"),
58
64
  ("version", "Show installed GemCode version"),
gemcode/tui/scrollback.py CHANGED
@@ -436,9 +436,36 @@ async def run_gemcode_scrollback_tui(
436
436
  continue
437
437
  prompt = slash.model_prompt or prompt
438
438
 
439
+ # Snapshot pre-turn capability state so we can detect routing-triggered changes.
440
+ _pre_dr = cfg.enable_deep_research
441
+ _pre_emb = cfg.enable_embeddings
442
+ _pre_cu = cfg.enable_computer_use
443
+ _pre_model = cfg.model
444
+
439
445
  apply_capability_routing(cfg, prompt, context="prompt")
440
446
  cfg.model = pick_effective_model(cfg, prompt)
441
447
 
448
+ # Capabilities and model are baked into the Runner at construction time.
449
+ # If routing changed any of them we must rebuild the runner so the new
450
+ # tools/model are actually used for this turn.
451
+ _routing_changed = (
452
+ cfg.enable_deep_research != _pre_dr
453
+ or cfg.enable_embeddings != _pre_emb
454
+ or cfg.enable_computer_use != _pre_cu
455
+ or cfg.model != _pre_model
456
+ )
457
+ if _routing_changed:
458
+ try:
459
+ close_fn = getattr(runner, "close", None)
460
+ if close_fn:
461
+ maybe = close_fn()
462
+ if asyncio.iscoroutine(maybe):
463
+ await maybe
464
+ except Exception:
465
+ pass
466
+ from gemcode.session_runtime import create_runner as _create_runner_rt
467
+ runner = _create_runner_rt(cfg, extra_tools=extra_tools)
468
+
442
469
  current_message = types.Content(role="user", parts=[types.Part(text=prompt)])
443
470
  do_reset = True
444
471
  def _normalize_ws(s: str) -> str:
@@ -501,7 +528,7 @@ async def run_gemcode_scrollback_tui(
501
528
  if thought_text and not (
502
529
  buffered_final and _normalize_ws(thought_text) == _normalize_ws(final_text)
503
530
  ):
504
- show_full = bool(getattr(cfg, "show_full_thinking", False))
531
+ show_full = bool(cfg.show_full_thinking)
505
532
  if show_full:
506
533
  # Verbose mode: full thinking rendered as Markdown, like transcript mode.
507
534
  print(f" \u23bf {ansi.dim}\u2234 Thinking{ansi.reset}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.22
3
+ Version: 0.3.23
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -7,7 +7,7 @@ gemcode/callbacks.py,sha256=dxZhHsJDE-16nJ0OGe4udPkWRTOCVfSi2gBSR7MUWOM,20465
7
7
  gemcode/capability_routing.py,sha256=D8tvawmf_MSL94GVXgG9QhDvNaQVGqzA8tUFQ8XlftY,2894
8
8
  gemcode/cli.py,sha256=0b9hO86EILJ5xRg8fb1Sfmwh6vYi9Bp6tkOvsxOSIEU,25447
9
9
  gemcode/compaction.py,sha256=9YtA_qa23_8dHWVHx7AJwUduuI7jJQtq-m6sT8jgPWI,1186
10
- gemcode/config.py,sha256=yKdOPcl6KwH49LLHZgQoYLubwiKhW-5U-cZ1c-Zu8qE,12219
10
+ gemcode/config.py,sha256=xvvhJbMEBPjIotwnxoggTdXpfYaDPjVi5PCIy489610,12540
11
11
  gemcode/context_budget.py,sha256=Nhox9vFBtLbb7jtO7cyGW1MxtN7SVjlIeQ7d-cgGyKM,10544
12
12
  gemcode/context_warning.py,sha256=Q8mg5Vojj7EglPhsGAVL7vb8ROLuHVPgdzw25yw-Q2c,4263
13
13
  gemcode/credentials.py,sha256=04v-rLD8_Ams69FQdof2FwcL3ZgsroGUnMcHNQFuBZo,1296
@@ -25,8 +25,8 @@ gemcode/model_routing.py,sha256=Q42HZtXQa6rao2O2vYMHxohrTgD-wq4t7qGxU4_38Jg,4881
25
25
  gemcode/paths.py,sha256=U6cEH9jfIcSc4NO8Ke0jniZSiJTfCIJPvSMue3hR0ZU,768
26
26
  gemcode/permissions.py,sha256=9FmwTP_LLflahxS9KXvY3VPSra4e-h3OariOqnWIKDI,177
27
27
  gemcode/prompt_suggestions.py,sha256=h-W_9LlfagS91PyoMEjEjsCqoG4XmIh3QBypA59HyGw,2553
28
- gemcode/repl_commands.py,sha256=5gZaKR0-PX0APmi9Zkpfr-T4qm49fZYIqm53Ene56no,6897
29
- gemcode/repl_slash.py,sha256=DJvYhVc0tfIXPHZJD667iH_doB-60JDGyD3ghIwEF3s,13053
28
+ gemcode/repl_commands.py,sha256=nnJSibPKCR2unmcRf1pjQKHu8uirHHah-9pFN3Hw9js,7972
29
+ gemcode/repl_slash.py,sha256=AUw5JfQWRZJWSoJKXNunhS0dWTgGRgiSPjcXxNkZpjM,24900
30
30
  gemcode/session_runtime.py,sha256=Evqr6YNqB_O0V3omGjqD1ve_6kdpgwe7KFev9-WE_nA,3308
31
31
  gemcode/slash_commands.py,sha256=Qylzsj1notk0xN_hvd3CR4HD8g-l99UENDMcg1pKeBA,794
32
32
  gemcode/thinking.py,sha256=RanBf_x9fKv1o4DNyNXPLfOdn2xT0KybJb65nYgmMEE,4885
@@ -63,17 +63,17 @@ gemcode/tools/subtask.py,sha256=ur_6jnwnNzHSBtW96mB2N2A6zmALpydSV24Nkx0T6UQ,5683
63
63
  gemcode/tools/think.py,sha256=WrNATR-bi97aLkbSsOFOYYAGxbzihe9AnPDZfw3z5-Q,1704
64
64
  gemcode/tools/todo.py,sha256=d9aXiyT04r1RFZIk6qdVif17-_Oc3oi4ymDnsPBRg68,3143
65
65
  gemcode/tools/web.py,sha256=ULg1e3inG4FjPSUCYI8dVBzTrcCHINNRo76SIU9qw-A,4489
66
- gemcode/tui/input_handler.py,sha256=lB5R7mRGXwfEE2lpNLpGyNXT_iQ7Hvl3fYSmumgrDOw,7517
67
- gemcode/tui/scrollback.py,sha256=mEft7ptC45dnKAOx-Qau8DQ8Em45HIZnTXMbKbTCHBM,19362
66
+ gemcode/tui/input_handler.py,sha256=kYlESEQpdeoaBZEUwWrackSw_fzwShxiAH_7A_RNz8w,8056
67
+ gemcode/tui/scrollback.py,sha256=ujdYDfyVAofmPDlxpClJ4vFwgMphqricNJDxQlVbkCM,20396
68
68
  gemcode/tui/spinner.py,sha256=AJrApG5od-Sh40-5uWcNM9RHb5ax7gr-NbgAZmTbIYY,4848
69
69
  gemcode/tui/welcome_banner.py,sha256=aocl1lnoyLIM6RN4f65g3i0wRA71RqUlgPrGsXeVLW4,4387
70
70
  gemcode/tui/welcome_rich.py,sha256=8FEZzLXrzqly5JWiDgV9ooRV1LNXDk-CXV1a7K6ua-U,4048
71
71
  gemcode/web/__init__.py,sha256=EysmUAWs6g-lmMk4VFljKfaHVrEgb_FiIzwQmBdORJc,40
72
72
  gemcode/web/claude_sse_adapter.py,sha256=HcNp0Lh4DdBZBLOpstsqa-VzfqAUrRngZ6FSuJ-mIMg,8609
73
73
  gemcode/web/terminal_repl.py,sha256=k2irvFGbCY8gDm_pbirR7b_cakaeafcctoTIvnJkVXk,3902
74
- gemcode-0.3.22.dist-info/licenses/LICENSE,sha256=TD4524qn-W8Z07GTDnag-9jJPFutFZNB0a1WbMHPC54,8388
75
- gemcode-0.3.22.dist-info/METADATA,sha256=AJPmRUbFP8u5VWMxOzow9mz3dnZ-Uvx0wI-IYHWTEf0,23695
76
- gemcode-0.3.22.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
77
- gemcode-0.3.22.dist-info/entry_points.txt,sha256=cZdLTLDiHbks7OSUCuxCh66dCWeQdpLR8BozoqfEjV4,45
78
- gemcode-0.3.22.dist-info/top_level.txt,sha256=UYrjULLBY2bcgK6KI6flomJWmsbDXu7n0rvW2SWFrbo,8
79
- gemcode-0.3.22.dist-info/RECORD,,
74
+ gemcode-0.3.23.dist-info/licenses/LICENSE,sha256=TD4524qn-W8Z07GTDnag-9jJPFutFZNB0a1WbMHPC54,8388
75
+ gemcode-0.3.23.dist-info/METADATA,sha256=ZxsvHPJbnkeLZxuaAnsbQIbz8JjsZHuGplk6u4J15uc,23695
76
+ gemcode-0.3.23.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
77
+ gemcode-0.3.23.dist-info/entry_points.txt,sha256=cZdLTLDiHbks7OSUCuxCh66dCWeQdpLR8BozoqfEjV4,45
78
+ gemcode-0.3.23.dist-info/top_level.txt,sha256=UYrjULLBY2bcgK6KI6flomJWmsbDXu7n0rvW2SWFrbo,8
79
+ gemcode-0.3.23.dist-info/RECORD,,