gemcode 0.3.26__py3-none-any.whl → 0.3.27__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/tui/scrollback.py CHANGED
@@ -252,15 +252,26 @@ async def run_gemcode_scrollback_tui(
252
252
  REQUEST_CONFIRMATION_FC = _ADK_REQUEST_CONFIRMATION
253
253
 
254
254
  def _get_confirmation_fcs(events: list) -> list[types.FunctionCall]:
255
- out: list[types.FunctionCall] = []
256
- for ev in events:
255
+ """Return confirmation FCs from the LAST event that contains them.
256
+
257
+ The ADK runner expects function responses only for the function calls
258
+ in the most recent event. Sending responses for FCs from earlier events
259
+ in the same batch raises:
260
+ ValueError: Last response event should only contain the responses for
261
+ the function calls in the same function call event.
262
+ So we scan backwards and return only the first (= last) match.
263
+ """
264
+ for ev in reversed(events):
257
265
  try:
258
- for fc in ev.get_function_calls() or []:
259
- if getattr(fc, "name", None) == _ADK_REQUEST_CONFIRMATION:
260
- out.append(fc)
266
+ fcs = [
267
+ fc for fc in (ev.get_function_calls() or [])
268
+ if getattr(fc, "name", None) == _ADK_REQUEST_CONFIRMATION
269
+ ]
270
+ if fcs:
271
+ return fcs
261
272
  except Exception:
262
273
  continue
263
- return out
274
+ return []
264
275
 
265
276
  def _extract_tool_and_hint(fc: types.FunctionCall) -> tuple[str, str]:
266
277
  tool_name = "unknown_tool"
@@ -527,26 +538,40 @@ async def run_gemcode_scrollback_tui(
527
538
  # as different phases of the turn complete.
528
539
  _start_anim("Thinking\u2026")
529
540
 
530
- async for ev in runner.run_async(**kwargs):
531
- events.append(ev)
532
- _render_tool_calls(ev)
533
- _render_tool_results(ev)
534
- try:
535
- if not ev.content or not ev.content.parts:
536
- continue
537
- if not getattr(ev, "author", None) or ev.author == "user":
538
- continue
539
- for part in ev.content.parts:
540
- delta = getattr(part, "text", None)
541
- if not delta:
541
+ try:
542
+ async for ev in runner.run_async(**kwargs):
543
+ events.append(ev)
544
+ _render_tool_calls(ev)
545
+ _render_tool_results(ev)
546
+ try:
547
+ if not ev.content or not ev.content.parts:
542
548
  continue
543
- assistant_wrote_text = True
544
- if getattr(part, "thought", None):
545
- buffered_thought.append(delta)
546
- else:
547
- buffered_final.append(delta)
548
- except Exception:
549
- continue
549
+ if not getattr(ev, "author", None) or ev.author == "user":
550
+ continue
551
+ for part in ev.content.parts:
552
+ delta = getattr(part, "text", None)
553
+ if not delta:
554
+ continue
555
+ assistant_wrote_text = True
556
+ if getattr(part, "thought", None):
557
+ buffered_thought.append(delta)
558
+ else:
559
+ buffered_final.append(delta)
560
+ except Exception:
561
+ continue
562
+ except Exception as _turn_err:
563
+ # Catch runner errors (e.g. ADK ValueError from mismatched function
564
+ # response IDs) so a single bad turn doesn't crash the whole TUI.
565
+ _stop_anim()
566
+ print(
567
+ f"\n {ansi.blue_warn}[gemcode] turn error: "
568
+ f"{type(_turn_err).__name__}: {_turn_err}{ansi.reset}"
569
+ )
570
+ print(
571
+ f" {ansi.dim}The agent encountered an internal error on this turn. "
572
+ f"Please send your message again.{ansi.reset}\n"
573
+ )
574
+ break
550
575
 
551
576
  _stop_anim() # ensure spinner is gone before printing the response
552
577
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.26
3
+ Version: 0.3.27
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -65,16 +65,16 @@ gemcode/tools/think.py,sha256=WrNATR-bi97aLkbSsOFOYYAGxbzihe9AnPDZfw3z5-Q,1704
65
65
  gemcode/tools/todo.py,sha256=d9aXiyT04r1RFZIk6qdVif17-_Oc3oi4ymDnsPBRg68,3143
66
66
  gemcode/tools/web.py,sha256=ULg1e3inG4FjPSUCYI8dVBzTrcCHINNRo76SIU9qw-A,4489
67
67
  gemcode/tui/input_handler.py,sha256=rCSzV5Ucc-nZTBbY8KKTDS9einNrgMzvI_NGcMls9e8,8147
68
- gemcode/tui/scrollback.py,sha256=f14MSfDM4dryDWWG3vfTuzkV4mJfFbz2Yd7gF9S4pXs,23455
68
+ gemcode/tui/scrollback.py,sha256=zc91bA1jPQdluwy5eUFX3-lElYhaaSBIyOKQ0bj-zbA,24521
69
69
  gemcode/tui/spinner.py,sha256=AJrApG5od-Sh40-5uWcNM9RHb5ax7gr-NbgAZmTbIYY,4848
70
70
  gemcode/tui/welcome_banner.py,sha256=aocl1lnoyLIM6RN4f65g3i0wRA71RqUlgPrGsXeVLW4,4387
71
71
  gemcode/tui/welcome_rich.py,sha256=8FEZzLXrzqly5JWiDgV9ooRV1LNXDk-CXV1a7K6ua-U,4048
72
72
  gemcode/web/__init__.py,sha256=EysmUAWs6g-lmMk4VFljKfaHVrEgb_FiIzwQmBdORJc,40
73
73
  gemcode/web/claude_sse_adapter.py,sha256=HcNp0Lh4DdBZBLOpstsqa-VzfqAUrRngZ6FSuJ-mIMg,8609
74
74
  gemcode/web/terminal_repl.py,sha256=k2irvFGbCY8gDm_pbirR7b_cakaeafcctoTIvnJkVXk,3902
75
- gemcode-0.3.26.dist-info/licenses/LICENSE,sha256=TD4524qn-W8Z07GTDnag-9jJPFutFZNB0a1WbMHPC54,8388
76
- gemcode-0.3.26.dist-info/METADATA,sha256=gvuLPIdccTr2APbK1N6Zjp9MwO9Uw7k6sS6C71ckrXU,23695
77
- gemcode-0.3.26.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
78
- gemcode-0.3.26.dist-info/entry_points.txt,sha256=cZdLTLDiHbks7OSUCuxCh66dCWeQdpLR8BozoqfEjV4,45
79
- gemcode-0.3.26.dist-info/top_level.txt,sha256=UYrjULLBY2bcgK6KI6flomJWmsbDXu7n0rvW2SWFrbo,8
80
- gemcode-0.3.26.dist-info/RECORD,,
75
+ gemcode-0.3.27.dist-info/licenses/LICENSE,sha256=TD4524qn-W8Z07GTDnag-9jJPFutFZNB0a1WbMHPC54,8388
76
+ gemcode-0.3.27.dist-info/METADATA,sha256=NQcP6nPPB0OOp9Z0_KLV7x3fZWEb77Ld7uNCLJFXObE,23695
77
+ gemcode-0.3.27.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
78
+ gemcode-0.3.27.dist-info/entry_points.txt,sha256=cZdLTLDiHbks7OSUCuxCh66dCWeQdpLR8BozoqfEjV4,45
79
+ gemcode-0.3.27.dist-info/top_level.txt,sha256=UYrjULLBY2bcgK6KI6flomJWmsbDXu7n0rvW2SWFrbo,8
80
+ gemcode-0.3.27.dist-info/RECORD,,