gemcode 0.3.56__tar.gz → 0.3.58__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. {gemcode-0.3.56/src/gemcode.egg-info → gemcode-0.3.58}/PKG-INFO +1 -1
  2. {gemcode-0.3.56 → gemcode-0.3.58}/pyproject.toml +1 -1
  3. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/session_runtime.py +81 -3
  4. {gemcode-0.3.56 → gemcode-0.3.58/src/gemcode.egg-info}/PKG-INFO +1 -1
  5. {gemcode-0.3.56 → gemcode-0.3.58}/LICENSE +0 -0
  6. {gemcode-0.3.56 → gemcode-0.3.58}/MANIFEST.in +0 -0
  7. {gemcode-0.3.56 → gemcode-0.3.58}/README.md +0 -0
  8. {gemcode-0.3.56 → gemcode-0.3.58}/setup.cfg +0 -0
  9. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/__init__.py +0 -0
  10. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/__main__.py +0 -0
  11. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/agent.py +0 -0
  12. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/audit.py +0 -0
  13. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/autocompact.py +0 -0
  14. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/callbacks.py +0 -0
  15. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/capability_routing.py +0 -0
  16. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/cli.py +0 -0
  17. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/compaction.py +0 -0
  18. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/computer_use/__init__.py +0 -0
  19. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/computer_use/browser_computer.py +0 -0
  20. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/config.py +0 -0
  21. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/context_budget.py +0 -0
  22. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/context_warning.py +0 -0
  23. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/credentials.py +0 -0
  24. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/hitl_session.py +0 -0
  25. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/hooks.py +0 -0
  26. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/intent_classifier.py +0 -0
  27. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/interactions.py +0 -0
  28. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/invoke.py +0 -0
  29. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/kairos_daemon.py +0 -0
  30. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/limits.py +0 -0
  31. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/live_audio_engine.py +0 -0
  32. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/logging_config.py +0 -0
  33. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/mcp_loader.py +0 -0
  34. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/memory/__init__.py +0 -0
  35. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/memory/embedding_memory_service.py +0 -0
  36. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/memory/file_memory_service.py +0 -0
  37. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/modality_tools.py +0 -0
  38. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/model_errors.py +0 -0
  39. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/model_routing.py +0 -0
  40. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/openapi_loader.py +0 -0
  41. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/paths.py +0 -0
  42. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/permissions.py +0 -0
  43. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/plugins/__init__.py +0 -0
  44. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  45. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  46. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/pricing.py +0 -0
  47. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/prompt_suggestions.py +0 -0
  48. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/__init__.py +0 -0
  49. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/config.py +0 -0
  50. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/deps.py +0 -0
  51. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/engine.py +0 -0
  52. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/stop_hooks.py +0 -0
  53. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/token_budget.py +0 -0
  54. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/query/transitions.py +0 -0
  55. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/refine.py +0 -0
  56. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/repl_commands.py +0 -0
  57. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/repl_slash.py +0 -0
  58. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/review_agent.py +0 -0
  59. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/session_store.py +0 -0
  60. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/slash_commands.py +0 -0
  61. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/thinking.py +0 -0
  62. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tool_prompt_manifest.py +0 -0
  63. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tool_registry.py +0 -0
  64. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/__init__.py +0 -0
  65. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/bash.py +0 -0
  66. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/browser.py +0 -0
  67. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/edit.py +0 -0
  68. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/filesystem.py +0 -0
  69. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/notes.py +0 -0
  70. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/search.py +0 -0
  71. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/shell.py +0 -0
  72. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/shell_gate.py +0 -0
  73. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/subtask.py +0 -0
  74. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/think.py +0 -0
  75. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/todo.py +0 -0
  76. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools/web.py +0 -0
  77. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tools_inspector.py +0 -0
  78. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/trust.py +0 -0
  79. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tui/input_handler.py +0 -0
  80. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tui/scrollback.py +0 -0
  81. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tui/spinner.py +0 -0
  82. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tui/welcome_banner.py +0 -0
  83. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/tui/welcome_rich.py +0 -0
  84. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/version.py +0 -0
  85. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/vertex.py +0 -0
  86. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/web/__init__.py +0 -0
  87. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/web/claude_sse_adapter.py +0 -0
  88. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/web/terminal_repl.py +0 -0
  89. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode/workspace_hints.py +0 -0
  90. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode.egg-info/SOURCES.txt +0 -0
  91. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode.egg-info/dependency_links.txt +0 -0
  92. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode.egg-info/entry_points.txt +0 -0
  93. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode.egg-info/requires.txt +0 -0
  94. {gemcode-0.3.56 → gemcode-0.3.58}/src/gemcode.egg-info/top_level.txt +0 -0
  95. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_agent_instruction.py +0 -0
  96. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_autocompact.py +0 -0
  97. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_capability_routing.py +0 -0
  98. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_claude_web_adapter_sse.py +0 -0
  99. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_cli_init.py +0 -0
  100. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_computer_use_permissions.py +0 -0
  101. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_context_budget.py +0 -0
  102. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_context_warning.py +0 -0
  103. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_credentials.py +0 -0
  104. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_interactive_permission_ask.py +0 -0
  105. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_kairos_scheduler.py +0 -0
  106. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_modality_tools.py +0 -0
  107. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_model_error_retry.py +0 -0
  108. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_model_errors.py +0 -0
  109. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_model_routing.py +0 -0
  110. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_paths.py +0 -0
  111. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_permissions.py +0 -0
  112. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_prompt_suggestions.py +0 -0
  113. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_repl_commands.py +0 -0
  114. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_repl_slash.py +0 -0
  115. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_slash_commands.py +0 -0
  116. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_thinking_config.py +0 -0
  117. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_token_budget.py +0 -0
  118. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_tool_context_circulation.py +0 -0
  119. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_tools.py +0 -0
  120. {gemcode-0.3.56 → gemcode-0.3.58}/tests/test_tools_inspector.py +0 -0
  121. {gemcode-0.3.56 → gemcode-0.3.58}/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.56
3
+ Version: 0.3.58
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.56"
7
+ version = "0.3.58"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -35,6 +35,60 @@ def session_db_path(cfg: GemCodeConfig) -> Path:
35
35
  return cfg.project_root / ".gemcode" / "sessions.sqlite"
36
36
 
37
37
 
38
+ def _wrap_computer_use_tools_with_safety_ack(llm_request) -> None:
39
+ """
40
+ Gemini Computer Use models may include `safety_decision` in tool call args.
41
+ The client must acknowledge it in the corresponding FunctionResponse or the
42
+ API returns HTTP 400.
43
+
44
+ ADK's ComputerUseTool returns only image/url by default, so we wrap the tool
45
+ functions to (a) ignore `safety_decision` for execution and (b) include
46
+ `safety_acknowledgement="true"` in the tool result when present.
47
+ """
48
+ try:
49
+ from google.adk.tools.computer_use.computer_use_tool import ComputerUseTool
50
+ except Exception:
51
+ return
52
+
53
+ try:
54
+ tools_dict = getattr(llm_request, "tools_dict", None)
55
+ if not isinstance(tools_dict, dict) or not tools_dict:
56
+ return
57
+ except Exception:
58
+ return
59
+
60
+ # Wrap each ComputerUseTool's underlying function in-place.
61
+ for tool_name, tool in list(tools_dict.items()):
62
+ try:
63
+ if not isinstance(tool, ComputerUseTool):
64
+ continue
65
+ original_func = getattr(tool, "func", None)
66
+ if original_func is None:
67
+ continue
68
+
69
+ async def wrapped(*, _orig=original_func, _tool_name=tool_name, **args):
70
+ sd = None
71
+ if isinstance(args, dict) and "safety_decision" in args:
72
+ sd = args.pop("safety_decision", None)
73
+ result = await _orig(**args)
74
+ if sd is None:
75
+ return result
76
+ # Acknowledge the safety decision as required by Gemini computer-use.
77
+ if isinstance(result, dict):
78
+ out = dict(result)
79
+ out["safety_acknowledgement"] = "true"
80
+ return out
81
+ return {"result": result, "safety_acknowledgement": "true"}
82
+
83
+ try:
84
+ wrapped.__name__ = tool_name
85
+ except Exception:
86
+ pass
87
+ tool.func = wrapped
88
+ except Exception:
89
+ continue
90
+
91
+
38
92
  def _playwright_available() -> bool:
39
93
  """
40
94
  Quick synchronous check: does a usable Playwright browser executable exist?
@@ -47,14 +101,37 @@ def _playwright_available() -> bool:
47
101
  This is called before building the runner so we can disable computer-use
48
102
  early and prevent model routing from switching to gemini-2.5-computer-use-*.
49
103
  """
104
+ # 1) Preferred: ask Playwright for the resolved executable path.
105
+ # This can fail in some environment-mismatch cases (package installed but driver
106
+ # cannot start), so we also do a cache-based probe below.
50
107
  try:
51
108
  from playwright.sync_api import sync_playwright
52
109
  with sync_playwright() as p:
53
- exe = p.chromium.executable_path
54
- return bool(exe) and Path(exe).exists()
110
+ exe = getattr(p.chromium, "executable_path", None)
111
+ if exe and Path(str(exe)).exists():
112
+ return True
113
+ except Exception:
114
+ pass
115
+
116
+ # 2) Fallback: check the default browser cache directly.
117
+ # This avoids false negatives when Playwright import/driver resolution is flaky,
118
+ # but browsers are present (common on macOS with mixed --user/system installs).
119
+ try:
120
+ cache_root = Path.home() / "Library" / "Caches" / "ms-playwright"
121
+ if not cache_root.exists():
122
+ return False
123
+ # macOS paths (Chromium.app or "Google Chrome for Testing.app")
124
+ mac_bins = list(cache_root.glob("chromium-*/*/Chromium.app/Contents/MacOS/Chromium"))
125
+ mac_bins += list(
126
+ cache_root.glob(
127
+ "chromium-*/*/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing"
128
+ )
129
+ )
130
+ if any(p.exists() for p in mac_bins):
131
+ return True
55
132
  except Exception:
56
133
  pass
57
- # playwright not installed at all
134
+
58
135
  return False
59
136
 
60
137
 
@@ -124,6 +201,7 @@ def _make_safe_computer_toolset(computer):
124
201
  await self._inner.process_llm_request(
125
202
  tool_context=tool_context, llm_request=llm_request
126
203
  )
204
+ _wrap_computer_use_tools_with_safety_ack(llm_request)
127
205
  except Exception as exc:
128
206
  if not self._broken:
129
207
  self._broken = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.56
3
+ Version: 0.3.58
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes