gemcode 0.3.50__tar.gz → 0.3.52__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.50/src/gemcode.egg-info → gemcode-0.3.52}/PKG-INFO +1 -1
- {gemcode-0.3.50 → gemcode-0.3.52}/pyproject.toml +1 -1
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/session_runtime.py +103 -70
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tui/input_handler.py +17 -3
- {gemcode-0.3.50 → gemcode-0.3.52/src/gemcode.egg-info}/PKG-INFO +1 -1
- {gemcode-0.3.50 → gemcode-0.3.52}/LICENSE +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/MANIFEST.in +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/README.md +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/setup.cfg +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/callbacks.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/cli.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/config.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/invoke.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/kairos_daemon.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/repl_slash.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/subtask.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tui/scrollback.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/version.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/web/claude_sse_adapter.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode.egg-info/SOURCES.txt +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_claude_web_adapter_sse.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_credentials.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_kairos_scheduler.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_paths.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_permissions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_tools.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.50 → gemcode-0.3.52}/tests/test_workspace_hints.py +0 -0
|
@@ -30,76 +30,109 @@ def session_db_path(cfg: GemCodeConfig) -> Path:
|
|
|
30
30
|
return cfg.project_root / ".gemcode" / "sessions.sqlite"
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
def _make_safe_computer_toolset(computer):
|
|
34
34
|
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for the current session instead of crashing every turn with an unhandled error.
|
|
38
|
-
|
|
39
|
-
When the underlying toolset fails for the *first* time a one-time warning is
|
|
40
|
-
printed to stderr so the user knows they need to run ``playwright install``.
|
|
41
|
-
Subsequent calls are silently no-ops so the session keeps working without
|
|
42
|
-
browser tools — the agent can still use all other tools normally.
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
def __init__(self, computer) -> None:
|
|
46
|
-
try:
|
|
47
|
-
from google.adk.tools.computer_use.computer_use_toolset import ComputerUseToolset
|
|
48
|
-
self._inner = ComputerUseToolset(computer=computer)
|
|
49
|
-
except Exception:
|
|
50
|
-
self._inner = None
|
|
51
|
-
self._broken = False
|
|
52
|
-
self._warned = False
|
|
53
|
-
|
|
54
|
-
def _warn_once(self, error: Exception) -> None:
|
|
55
|
-
if self._warned:
|
|
56
|
-
return
|
|
57
|
-
self._warned = True
|
|
58
|
-
import sys
|
|
59
|
-
msg = str(error)
|
|
60
|
-
if "playwright install" in msg.lower() or "executable doesn't exist" in msg.lower():
|
|
61
|
-
print(
|
|
62
|
-
"\n[gemcode] Browser (computer-use) is unavailable — Playwright browsers are not installed.\n"
|
|
63
|
-
" Run: playwright install chromium\n"
|
|
64
|
-
" Then restart GemCode with /computer on (or --computer flag).\n"
|
|
65
|
-
" Continuing without browser tools for this session.\n",
|
|
66
|
-
file=sys.stderr,
|
|
67
|
-
)
|
|
68
|
-
else:
|
|
69
|
-
print(
|
|
70
|
-
f"\n[gemcode] Browser (computer-use) failed to start: {msg!s:.200}\n"
|
|
71
|
-
" Continuing without browser tools for this session.\n",
|
|
72
|
-
file=sys.stderr,
|
|
73
|
-
)
|
|
35
|
+
Build a BaseToolset-compatible wrapper around ComputerUseToolset that catches
|
|
36
|
+
Playwright startup failures gracefully instead of crashing LlmAgent validation.
|
|
74
37
|
|
|
75
|
-
|
|
38
|
+
Must be a proper BaseToolset subclass (not a plain class) because ADK's Pydantic
|
|
39
|
+
model for LlmAgent validates each entry in `tools` against BaseTool | BaseToolset.
|
|
40
|
+
Returns a real BaseToolset subclass instance, or None if BaseToolset is unavailable.
|
|
41
|
+
"""
|
|
42
|
+
try:
|
|
43
|
+
from google.adk.tools.base_toolset import BaseToolset
|
|
44
|
+
except ImportError:
|
|
45
|
+
return None
|
|
76
46
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
self.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
47
|
+
class _SafeComputerUseToolset(BaseToolset):
|
|
48
|
+
"""Wraps ComputerUseToolset; degrades to a no-op if Playwright is missing."""
|
|
49
|
+
|
|
50
|
+
def __init__(self) -> None:
|
|
51
|
+
try:
|
|
52
|
+
from google.adk.tools.computer_use.computer_use_toolset import ComputerUseToolset
|
|
53
|
+
self._inner = ComputerUseToolset(computer=computer)
|
|
54
|
+
except Exception:
|
|
55
|
+
self._inner = None
|
|
56
|
+
self._broken = False
|
|
57
|
+
self._warned = False
|
|
58
|
+
|
|
59
|
+
def _warn_once(self, error: Exception) -> None:
|
|
60
|
+
if self._warned:
|
|
61
|
+
return
|
|
62
|
+
self._warned = True
|
|
63
|
+
import sys
|
|
64
|
+
msg = str(error)
|
|
65
|
+
if "playwright install" in msg.lower() or "executable doesn't exist" in msg.lower():
|
|
66
|
+
print(
|
|
67
|
+
"\n[gemcode] Browser (computer-use) is unavailable — Playwright browsers are not installed.\n"
|
|
68
|
+
" Run: playwright install chromium\n"
|
|
69
|
+
" Then restart GemCode with /computer on (or --computer flag).\n"
|
|
70
|
+
" Continuing without browser tools for this session.\n",
|
|
71
|
+
file=sys.stderr,
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
print(
|
|
75
|
+
f"\n[gemcode] Browser (computer-use) failed to start: {msg!s:.200}\n"
|
|
76
|
+
" Continuing without browser tools for this session.\n",
|
|
77
|
+
file=sys.stderr,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# ── BaseToolset required attribute ──────────────────────────────────────
|
|
81
|
+
@property
|
|
82
|
+
def tool_name_prefix(self) -> str:
|
|
83
|
+
if self._inner is not None:
|
|
84
|
+
try:
|
|
85
|
+
return self._inner.tool_name_prefix
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
return ""
|
|
89
|
+
|
|
90
|
+
# ── Core protocol methods ────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
async def process_llm_request(self, *, tool_context, llm_request) -> None:
|
|
93
|
+
if self._broken or self._inner is None:
|
|
94
|
+
return
|
|
95
|
+
try:
|
|
96
|
+
await self._inner.process_llm_request(
|
|
97
|
+
tool_context=tool_context, llm_request=llm_request
|
|
98
|
+
)
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
if not self._broken:
|
|
101
|
+
self._broken = True
|
|
102
|
+
self._warn_once(exc)
|
|
103
|
+
|
|
104
|
+
async def get_tools(self, readonly_context=None):
|
|
105
|
+
if self._broken or self._inner is None:
|
|
106
|
+
return []
|
|
107
|
+
try:
|
|
108
|
+
return await self._inner.get_tools(readonly_context)
|
|
109
|
+
except Exception as exc:
|
|
110
|
+
if not self._broken:
|
|
111
|
+
self._broken = True
|
|
112
|
+
self._warn_once(exc)
|
|
113
|
+
return []
|
|
114
|
+
|
|
115
|
+
async def close(self) -> None:
|
|
116
|
+
if self._inner is not None:
|
|
117
|
+
try:
|
|
118
|
+
await self._inner.close()
|
|
119
|
+
except Exception:
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
def __getattr__(self, name: str):
|
|
123
|
+
"""Proxy any other BaseToolset attributes ADK needs to the inner toolset."""
|
|
124
|
+
# Guard against infinite recursion for our own private attrs.
|
|
125
|
+
if name.startswith("_"):
|
|
126
|
+
raise AttributeError(name)
|
|
127
|
+
inner = object.__getattribute__(self, "_inner")
|
|
128
|
+
if inner is not None:
|
|
129
|
+
try:
|
|
130
|
+
return getattr(inner, name)
|
|
131
|
+
except AttributeError:
|
|
132
|
+
pass
|
|
133
|
+
raise AttributeError(f"'_SafeComputerUseToolset' has no attribute '{name}'")
|
|
134
|
+
|
|
135
|
+
return _SafeComputerUseToolset()
|
|
103
136
|
|
|
104
137
|
|
|
105
138
|
def _build_artifact_service(cfg: GemCodeConfig):
|
|
@@ -158,15 +191,15 @@ def create_runner(cfg: GemCodeConfig, extra_tools: list | None = None) -> Runner
|
|
|
158
191
|
viewport_w = int(os.environ.get("GEMCODE_BROWSER_WIDTH", "1280"))
|
|
159
192
|
viewport_h = int(os.environ.get("GEMCODE_BROWSER_HEIGHT", "720"))
|
|
160
193
|
from gemcode.computer_use.browser_computer import BrowserComputer
|
|
161
|
-
from google.adk.tools.computer_use.computer_use_toolset import ComputerUseToolset
|
|
162
194
|
|
|
163
195
|
computer = BrowserComputer(
|
|
164
196
|
headless=headless,
|
|
165
197
|
viewport_size=(viewport_w, viewport_h),
|
|
166
198
|
)
|
|
167
|
-
computer_toolset =
|
|
199
|
+
computer_toolset = _make_safe_computer_toolset(computer)
|
|
168
200
|
merged_extra_tools = list(merged_extra_tools or [])
|
|
169
|
-
|
|
201
|
+
if computer_toolset is not None:
|
|
202
|
+
merged_extra_tools.append(computer_toolset)
|
|
170
203
|
|
|
171
204
|
# Standalone read-only browser tools (browser_screenshot, browser_get_text, etc.)
|
|
172
205
|
from gemcode.tools.browser import build_browser_inspection_tools
|
|
@@ -184,8 +184,18 @@ class GemCodeInputHandler:
|
|
|
184
184
|
"""Ctrl+C clears current line (like a real shell)."""
|
|
185
185
|
event.app.current_buffer.reset()
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
@kb.add("enter")
|
|
188
|
+
def _submit(event):
|
|
189
|
+
"""Enter always submits — even in multiline mode (for pasted code)."""
|
|
190
|
+
event.current_buffer.validate_and_handle()
|
|
191
|
+
|
|
192
|
+
@kb.add("escape", "enter", eager=True)
|
|
193
|
+
@kb.add("c-j") # Ctrl+J = manual newline inside a message
|
|
194
|
+
def _newline(event):
|
|
195
|
+
"""Meta+Enter or Ctrl+J inserts a real newline without submitting."""
|
|
196
|
+
event.current_buffer.insert_text("\n")
|
|
197
|
+
|
|
198
|
+
# Rows reserved for the / command popup.
|
|
189
199
|
try:
|
|
190
200
|
_menu_rows = int(os.environ.get("GEMCODE_TUI_RESERVE_MENU_LINES", "12"))
|
|
191
201
|
except ValueError:
|
|
@@ -202,8 +212,12 @@ class GemCodeInputHandler:
|
|
|
202
212
|
mouse_support=False,
|
|
203
213
|
complete_in_thread=True,
|
|
204
214
|
reserve_space_for_menu=_menu_rows,
|
|
205
|
-
# Single-column popup with description column (like VS Code)
|
|
206
215
|
complete_style="COLUMN",
|
|
216
|
+
# Multiline=True so pasted code (with \n) lands in the buffer
|
|
217
|
+
# as one block rather than submitting line-by-line.
|
|
218
|
+
# Our Enter binding above overrides the default "add newline"
|
|
219
|
+
# behaviour so single-line prompts work exactly as before.
|
|
220
|
+
multiline=True,
|
|
207
221
|
)
|
|
208
222
|
|
|
209
223
|
def is_interactive(self) -> bool:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|