pygpt-net 2.7.3__py3-none-any.whl → 2.7.5__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.
Files changed (157) hide show
  1. pygpt_net/CHANGELOG.txt +15 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +382 -350
  4. pygpt_net/app_core.py +4 -2
  5. pygpt_net/controller/__init__.py +5 -1
  6. pygpt_net/controller/assistant/assistant.py +1 -4
  7. pygpt_net/controller/assistant/batch.py +5 -504
  8. pygpt_net/controller/assistant/editor.py +5 -5
  9. pygpt_net/controller/assistant/files.py +16 -16
  10. pygpt_net/controller/chat/attachment.py +5 -1
  11. pygpt_net/controller/chat/handler/google_stream.py +307 -1
  12. pygpt_net/controller/chat/handler/worker.py +8 -1
  13. pygpt_net/controller/chat/image.py +15 -3
  14. pygpt_net/controller/dialogs/confirm.py +73 -101
  15. pygpt_net/controller/files/files.py +3 -1
  16. pygpt_net/controller/lang/mapping.py +9 -9
  17. pygpt_net/controller/layout/layout.py +2 -2
  18. pygpt_net/controller/painter/capture.py +50 -1
  19. pygpt_net/controller/presets/presets.py +2 -1
  20. pygpt_net/controller/remote_store/__init__.py +12 -0
  21. pygpt_net/{provider/core/assistant_file/db_sqlite → controller/remote_store/google}/__init__.py +2 -2
  22. pygpt_net/controller/remote_store/google/batch.py +402 -0
  23. pygpt_net/controller/remote_store/google/store.py +615 -0
  24. pygpt_net/controller/remote_store/openai/__init__.py +12 -0
  25. pygpt_net/controller/remote_store/openai/batch.py +524 -0
  26. pygpt_net/controller/{assistant → remote_store/openai}/store.py +63 -60
  27. pygpt_net/controller/remote_store/remote_store.py +35 -0
  28. pygpt_net/controller/theme/nodes.py +2 -1
  29. pygpt_net/controller/ui/mode.py +5 -1
  30. pygpt_net/controller/ui/ui.py +36 -2
  31. pygpt_net/core/assistants/assistants.py +3 -15
  32. pygpt_net/core/db/database.py +5 -3
  33. pygpt_net/core/filesystem/url.py +4 -1
  34. pygpt_net/core/locale/placeholder.py +35 -0
  35. pygpt_net/core/remote_store/__init__.py +12 -0
  36. pygpt_net/core/remote_store/google/__init__.py +11 -0
  37. pygpt_net/core/remote_store/google/files.py +224 -0
  38. pygpt_net/core/remote_store/google/store.py +248 -0
  39. pygpt_net/core/remote_store/openai/__init__.py +11 -0
  40. pygpt_net/core/{assistants → remote_store/openai}/files.py +26 -19
  41. pygpt_net/core/{assistants → remote_store/openai}/store.py +32 -15
  42. pygpt_net/core/remote_store/remote_store.py +24 -0
  43. pygpt_net/core/render/web/helpers.py +5 -0
  44. pygpt_net/data/config/config.json +8 -5
  45. pygpt_net/data/config/models.json +77 -3
  46. pygpt_net/data/config/settings.json +45 -14
  47. pygpt_net/data/css/web-blocks.css +3 -0
  48. pygpt_net/data/css/web-chatgpt.css +3 -0
  49. pygpt_net/data/locale/locale.de.ini +43 -41
  50. pygpt_net/data/locale/locale.en.ini +56 -44
  51. pygpt_net/data/locale/locale.es.ini +43 -41
  52. pygpt_net/data/locale/locale.fr.ini +43 -41
  53. pygpt_net/data/locale/locale.it.ini +43 -41
  54. pygpt_net/data/locale/locale.pl.ini +43 -41
  55. pygpt_net/data/locale/locale.uk.ini +43 -41
  56. pygpt_net/data/locale/locale.zh.ini +43 -41
  57. pygpt_net/data/locale/plugin.cmd_history.de.ini +1 -1
  58. pygpt_net/data/locale/plugin.cmd_history.en.ini +1 -1
  59. pygpt_net/data/locale/plugin.cmd_history.es.ini +1 -1
  60. pygpt_net/data/locale/plugin.cmd_history.fr.ini +1 -1
  61. pygpt_net/data/locale/plugin.cmd_history.it.ini +1 -1
  62. pygpt_net/data/locale/plugin.cmd_history.pl.ini +1 -1
  63. pygpt_net/data/locale/plugin.cmd_history.uk.ini +1 -1
  64. pygpt_net/data/locale/plugin.cmd_history.zh.ini +1 -1
  65. pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +14 -0
  66. pygpt_net/data/locale/plugin.cmd_web.de.ini +1 -1
  67. pygpt_net/data/locale/plugin.cmd_web.en.ini +1 -1
  68. pygpt_net/data/locale/plugin.cmd_web.es.ini +1 -1
  69. pygpt_net/data/locale/plugin.cmd_web.fr.ini +1 -1
  70. pygpt_net/data/locale/plugin.cmd_web.it.ini +1 -1
  71. pygpt_net/data/locale/plugin.cmd_web.pl.ini +1 -1
  72. pygpt_net/data/locale/plugin.cmd_web.uk.ini +1 -1
  73. pygpt_net/data/locale/plugin.cmd_web.zh.ini +1 -1
  74. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +2 -2
  75. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +2 -2
  76. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +2 -2
  77. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +2 -2
  78. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +2 -2
  79. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +2 -2
  80. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +2 -2
  81. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +2 -2
  82. pygpt_net/item/assistant.py +1 -211
  83. pygpt_net/item/ctx.py +3 -1
  84. pygpt_net/item/store.py +238 -0
  85. pygpt_net/launcher.py +115 -55
  86. pygpt_net/migrations/Version20260102190000.py +35 -0
  87. pygpt_net/migrations/__init__.py +3 -1
  88. pygpt_net/plugin/cmd_mouse_control/config.py +470 -1
  89. pygpt_net/plugin/cmd_mouse_control/plugin.py +488 -22
  90. pygpt_net/plugin/cmd_mouse_control/worker.py +464 -87
  91. pygpt_net/plugin/cmd_mouse_control/worker_sandbox.py +729 -0
  92. pygpt_net/plugin/idx_llama_index/config.py +2 -2
  93. pygpt_net/preload.py +243 -0
  94. pygpt_net/provider/api/google/__init__.py +16 -54
  95. pygpt_net/provider/api/google/chat.py +546 -129
  96. pygpt_net/provider/api/google/computer.py +190 -0
  97. pygpt_net/provider/api/google/image.py +74 -6
  98. pygpt_net/provider/api/google/realtime/realtime.py +2 -2
  99. pygpt_net/provider/api/google/remote_tools.py +93 -0
  100. pygpt_net/provider/api/google/store.py +546 -0
  101. pygpt_net/provider/api/google/video.py +9 -4
  102. pygpt_net/provider/api/google/worker/__init__.py +0 -0
  103. pygpt_net/provider/api/google/worker/importer.py +392 -0
  104. pygpt_net/provider/api/openai/computer.py +10 -1
  105. pygpt_net/provider/api/openai/image.py +42 -19
  106. pygpt_net/provider/api/openai/store.py +6 -6
  107. pygpt_net/provider/api/openai/video.py +27 -2
  108. pygpt_net/provider/api/openai/worker/importer.py +24 -24
  109. pygpt_net/provider/api/x_ai/image.py +25 -2
  110. pygpt_net/provider/core/config/patch.py +23 -1
  111. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +3 -3
  112. pygpt_net/provider/core/model/patch.py +17 -3
  113. pygpt_net/provider/core/preset/json_file.py +13 -7
  114. pygpt_net/provider/core/{assistant_file → remote_file}/__init__.py +1 -1
  115. pygpt_net/provider/core/{assistant_file → remote_file}/base.py +9 -9
  116. pygpt_net/provider/core/remote_file/db_sqlite/__init__.py +12 -0
  117. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/patch.py +1 -1
  118. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/provider.py +23 -20
  119. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/storage.py +35 -27
  120. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/utils.py +5 -4
  121. pygpt_net/provider/core/{assistant_store → remote_store}/__init__.py +1 -1
  122. pygpt_net/provider/core/{assistant_store → remote_store}/base.py +10 -10
  123. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/__init__.py +1 -1
  124. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/patch.py +1 -1
  125. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/provider.py +16 -15
  126. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/storage.py +30 -23
  127. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/utils.py +5 -4
  128. pygpt_net/provider/core/{assistant_store → remote_store}/json_file.py +9 -9
  129. pygpt_net/provider/llms/google.py +2 -2
  130. pygpt_net/ui/base/config_dialog.py +3 -2
  131. pygpt_net/ui/dialog/assistant.py +3 -3
  132. pygpt_net/ui/dialog/plugins.py +3 -1
  133. pygpt_net/ui/dialog/remote_store_google.py +539 -0
  134. pygpt_net/ui/dialog/{assistant_store.py → remote_store_openai.py} +95 -95
  135. pygpt_net/ui/dialogs.py +5 -3
  136. pygpt_net/ui/layout/chat/attachments_uploaded.py +3 -3
  137. pygpt_net/ui/layout/chat/input.py +20 -2
  138. pygpt_net/ui/layout/chat/painter.py +6 -4
  139. pygpt_net/ui/layout/toolbox/computer_env.py +26 -8
  140. pygpt_net/ui/layout/toolbox/image.py +5 -5
  141. pygpt_net/ui/layout/toolbox/video.py +5 -4
  142. pygpt_net/ui/main.py +84 -3
  143. pygpt_net/ui/menu/tools.py +13 -5
  144. pygpt_net/ui/widget/dialog/base.py +3 -10
  145. pygpt_net/ui/widget/dialog/remote_store_google.py +56 -0
  146. pygpt_net/ui/widget/dialog/{assistant_store.py → remote_store_openai.py} +9 -9
  147. pygpt_net/ui/widget/element/button.py +4 -4
  148. pygpt_net/ui/widget/lists/remote_store_google.py +248 -0
  149. pygpt_net/ui/widget/lists/{assistant_store.py → remote_store_openai.py} +21 -21
  150. pygpt_net/ui/widget/option/checkbox_list.py +47 -9
  151. pygpt_net/ui/widget/option/combo.py +158 -4
  152. pygpt_net/ui/widget/textarea/input_extra.py +664 -0
  153. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/METADATA +48 -9
  154. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/RECORD +157 -130
  155. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/LICENSE +0 -0
  156. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/WHEEL +0 -0
  157. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/entry_points.txt +0 -0
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.07.14 00:00:00 #
9
+ # Updated Date: 2026.01.01 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.core.types import MODEL_DEFAULT_MINI
@@ -65,7 +65,7 @@ class Config(BaseConfig):
65
65
  use="models",
66
66
  value=MODEL_DEFAULT_MINI,
67
67
  label="Model for question preparation",
68
- description="Model used to prepare question before asking Llama-index, default: gpt-40-mini",
68
+ description="Model used to prepare question before asking Llama-index, default: gpt-4o-mini",
69
69
  tooltip="Model",
70
70
  )
71
71
  plugin.add_option(
pygpt_net/preload.py ADDED
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2025.12.31 17:00:00 #
10
+ # ================================================== #
11
+
12
+ # -------------------------------------------------- #
13
+ # Lightweight splash window (separate process)
14
+ # -------------------------------------------------- #
15
+ def _splash_main(conn, title="PyGPT", message="Loading…"):
16
+ """
17
+ Minimal splash process using PySide6. Runs its own event loop and
18
+ listens for commands on a Pipe: {"type": "msg", "text": "..."} or {"type": "quit"}.
19
+ """
20
+ try:
21
+ # Import locally to keep the main process import path untouched
22
+ from PySide6 import QtCore, QtWidgets
23
+ except Exception:
24
+ return
25
+
26
+ try:
27
+ # Enable HiDPI (safe defaults)
28
+ try:
29
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
30
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
31
+ except Exception:
32
+ pass
33
+
34
+ app = QtWidgets.QApplication(["pygpt_splash"])
35
+
36
+ # Root window styled as splash
37
+ root = QtWidgets.QWidget(
38
+ None,
39
+ QtCore.Qt.SplashScreen
40
+ | QtCore.Qt.FramelessWindowHint
41
+ | QtCore.Qt.WindowStaysOnTopHint
42
+ )
43
+ root.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
44
+ root.setObjectName("SplashRoot")
45
+
46
+ panel = QtWidgets.QFrame(root)
47
+ panel.setObjectName("SplashPanel")
48
+ panel.setStyleSheet("""
49
+ #SplashPanel {
50
+ background-color: rgba(30, 30, 30, 230);
51
+ border-radius: 12px;
52
+ }
53
+ QLabel { color: #ffffff; }
54
+ """)
55
+ layout = QtWidgets.QVBoxLayout(panel)
56
+ layout.setContentsMargins(16, 16, 16, 16)
57
+ layout.setSpacing(8)
58
+
59
+ lbl_title = QtWidgets.QLabel(title, panel)
60
+ lbl_title.setAlignment(QtCore.Qt.AlignCenter)
61
+ lbl_title.setStyleSheet("font-size: 16px; font-weight: 600;")
62
+
63
+ lbl_wait = QtWidgets.QLabel("Initializing...")
64
+ lbl_wait.setAlignment(QtCore.Qt.AlignCenter)
65
+ lbl_wait.setStyleSheet("font-size: 12px;")
66
+
67
+ lbl_msg = QtWidgets.QLabel(message, panel)
68
+ lbl_msg.setAlignment(QtCore.Qt.AlignCenter)
69
+ lbl_msg.setStyleSheet("font-size: 12px;")
70
+
71
+ bar = QtWidgets.QProgressBar(panel)
72
+ bar.setRange(0, 0)
73
+ bar.setTextVisible(False)
74
+ bar.setFixedHeight(8)
75
+ bar.setStyleSheet("QProgressBar { border: 0px; border-radius: 4px; } "
76
+ "QProgressBar::chunk { background-color: #3f3f3f; }")
77
+
78
+ layout.addWidget(lbl_title)
79
+ layout.addWidget(lbl_msg)
80
+ layout.addWidget(bar)
81
+ layout.addWidget(lbl_wait)
82
+
83
+ panel.setFixedSize(360, 120)
84
+ panel.move(0, 0)
85
+ root.resize(panel.size())
86
+
87
+ # Center on primary screen
88
+ screen = app.primaryScreen()
89
+ if screen:
90
+ geo = screen.availableGeometry()
91
+ root.move(geo.center() - root.rect().center())
92
+
93
+ # Ensure initial transparency for fade-in
94
+ try:
95
+ root.setWindowOpacity(0.0)
96
+ except Exception:
97
+ pass
98
+
99
+ root.show()
100
+
101
+ # Fade-in on start (non-blocking, resilient to platform limitations)
102
+ try:
103
+ def _start_fade_in():
104
+ try:
105
+ anim = QtCore.QPropertyAnimation(root, b"windowOpacity")
106
+ anim.setDuration(300)
107
+ anim.setStartValue(0.0)
108
+ anim.setEndValue(1.0)
109
+ root._fade_in_anim = anim # keep reference to avoid GC
110
+ anim.start()
111
+ except Exception:
112
+ try:
113
+ root.setWindowOpacity(1.0)
114
+ except Exception:
115
+ pass
116
+
117
+ QtCore.QTimer.singleShot(0, _start_fade_in)
118
+ except Exception:
119
+ try:
120
+ root.setWindowOpacity(1.0)
121
+ except Exception:
122
+ pass
123
+
124
+ # Poll the pipe for messages and close requests
125
+ timer = QtCore.QTimer()
126
+ timer.setInterval(80)
127
+
128
+ def poll():
129
+ try:
130
+ if conn.poll():
131
+ msg = conn.recv()
132
+ if isinstance(msg, dict):
133
+ t = msg.get("type")
134
+ if t == "quit":
135
+ # Stop fade-in if it is running to avoid conflicting animations
136
+ try:
137
+ if hasattr(root, "_fade_in_anim") and root._fade_in_anim is not None:
138
+ root._fade_in_anim.stop()
139
+ except Exception:
140
+ pass
141
+ # Fade-out and quit
142
+ try:
143
+ anim = QtCore.QPropertyAnimation(root, b"windowOpacity")
144
+ anim.setDuration(180)
145
+ anim.setStartValue(root.windowOpacity())
146
+ anim.setEndValue(0.0)
147
+ anim.finished.connect(app.quit)
148
+ # Keep reference to avoid GC
149
+ root._fade_anim = anim
150
+ anim.start()
151
+ except Exception:
152
+ app.quit()
153
+ elif t == "msg":
154
+ text = msg.get("text", "")
155
+ if text:
156
+ lbl_msg.setText(text)
157
+ elif isinstance(msg, str):
158
+ if msg.lower() == "quit":
159
+ app.quit()
160
+ except (EOFError, OSError):
161
+ # Parent died or pipe closed: exit
162
+ app.quit()
163
+
164
+ timer.timeout.connect(poll)
165
+ timer.start()
166
+
167
+ # Failsafe timeout (can be overridden via env)
168
+ import os as _os
169
+ timeout_ms = int(_os.environ.get("PYGPT_SPLASH_TIMEOUT", "120000"))
170
+ killer = QtCore.QTimer()
171
+ killer.setSingleShot(True)
172
+ killer.timeout.connect(app.quit)
173
+ killer.start(timeout_ms)
174
+
175
+ app.exec()
176
+ except Exception:
177
+ # No crash propagation to main app
178
+ pass
179
+
180
+
181
+ class _Preloader:
182
+ """
183
+ Controller for the splash subprocess.
184
+ """
185
+
186
+ def __init__(self, proc, conn):
187
+ self._proc = proc
188
+ self._conn = conn
189
+
190
+ def set_message(self, text):
191
+ try:
192
+ if self._conn:
193
+ self._conn.send({"type": "msg", "text": str(text)})
194
+ except Exception:
195
+ pass
196
+
197
+ def close(self, wait=True, timeout=2.0):
198
+ try:
199
+ if self._conn:
200
+ try:
201
+ self._conn.send({"type": "quit"})
202
+ except Exception:
203
+ pass
204
+ finally:
205
+ if wait and self._proc is not None:
206
+ self._proc.join(timeout=timeout)
207
+ if self._proc is not None and self._proc.is_alive():
208
+ try:
209
+ self._proc.terminate()
210
+ except Exception:
211
+ pass
212
+ self._conn = None
213
+ self._proc = None
214
+
215
+
216
+ def _start_preloader(title="PyGPT", message="Loading…"):
217
+ """
218
+ Start splash as a separate process using 'spawn' on every OS.
219
+ Returns a _Preloader controller or None if failed.
220
+ """
221
+ try:
222
+ import multiprocessing as mp
223
+ try:
224
+ ctx = mp.get_context("spawn")
225
+ except ValueError:
226
+ ctx = mp
227
+
228
+ parent_conn, child_conn = ctx.Pipe(duplex=True)
229
+ proc = ctx.Process(
230
+ target=_splash_main,
231
+ args=(child_conn, title, message),
232
+ daemon=True
233
+ )
234
+ proc.start()
235
+
236
+ try:
237
+ child_conn.close()
238
+ except Exception:
239
+ pass
240
+
241
+ return _Preloader(proc, parent_conn)
242
+ except Exception:
243
+ return None
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.12.25 20:00:00 #
9
+ # Updated Date: 2026.01.02 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -22,16 +22,20 @@ from pygpt_net.core.types import (
22
22
  MODE_COMPLETION,
23
23
  MODE_IMAGE,
24
24
  MODE_RESEARCH,
25
+ MODE_COMPUTER,
25
26
  )
26
27
  from pygpt_net.core.bridge.context import BridgeContext
27
28
  from pygpt_net.item.model import ModelItem
28
29
 
29
30
  from .chat import Chat
31
+ from .computer import Computer
30
32
  from .vision import Vision
31
33
  from .tools import Tools
32
34
  from .audio import Audio
33
35
  from .image import Image
34
36
  from .realtime import Realtime
37
+ from .remote_tools import RemoteTools
38
+ from .store import Store
35
39
  from .video import Video
36
40
  from .music import Music
37
41
 
@@ -51,6 +55,9 @@ class ApiGoogle:
51
55
  self.realtime = Realtime(window)
52
56
  self.video = Video(window)
53
57
  self.music = Music(window)
58
+ self.computer = Computer(window)
59
+ self.remote_tools = RemoteTools(window)
60
+ self.store = Store(window)
54
61
  self.client: Optional[genai.Client] = None
55
62
  self.locked = False
56
63
  self.last_client_args: Optional[Dict[str, Any]] = None
@@ -125,7 +132,13 @@ class ApiGoogle:
125
132
  used_tokens = 0
126
133
  response = None
127
134
 
128
- if mode in [MODE_COMPLETION, MODE_CHAT, MODE_AUDIO, MODE_RESEARCH]:
135
+ if mode in [
136
+ MODE_COMPLETION,
137
+ MODE_CHAT,
138
+ MODE_AUDIO,
139
+ MODE_RESEARCH,
140
+ MODE_COMPUTER
141
+ ]:
129
142
 
130
143
  # Live API for audio streaming
131
144
  if mode == MODE_AUDIO and stream:
@@ -226,7 +239,7 @@ class ApiGoogle:
226
239
  """
227
240
  # with remote tools
228
241
  base_tools = self.tools.prepare(model, functions)
229
- remote_tools = self.build_remote_tools(model)
242
+ remote_tools = self.remote_tools.build_remote_tools(model)
230
243
  tools = (base_tools or []) + (remote_tools or [])
231
244
  """
232
245
 
@@ -262,57 +275,6 @@ class ApiGoogle:
262
275
  finally:
263
276
  self.locked = False
264
277
 
265
- def build_remote_tools(self, model: ModelItem = None) -> list:
266
- """
267
- Build Google GenAI remote tools based on config flags.
268
- - remote_tools.google.web_search: enables grounding via Google Search (Gemini 2.x)
269
- or GoogleSearchRetrieval (Gemini 1.5 fallback).
270
- - remote_tools.google.code_interpreter: enables code execution tool.
271
-
272
- Returns a list of gtypes.Tool objects (can be empty).
273
-
274
- :param model: ModelItem
275
- :return: list of gtypes.Tool
276
- """
277
- tools: list = []
278
- cfg = self.window.core.config
279
- model_id = (model.id if model and getattr(model, "id", None) else "").lower()
280
- is_web = self.window.controller.chat.remote_tools.enabled(model, "web_search") # get global config
281
-
282
- # Google Search tool
283
- if is_web and "image" not in model.id:
284
- try:
285
- if not model_id.startswith("gemini-1.5") and not model_id.startswith("models/gemini-1.5"):
286
- # Gemini 2.x uses GoogleSearch
287
- tools.append(gtypes.Tool(google_search=gtypes.GoogleSearch()))
288
- else:
289
- # Gemini 1.5 fallback uses GoogleSearchRetrieval
290
- # Note: Supported only for 1.5 models.
291
- tools.append(gtypes.Tool(
292
- google_search_retrieval=gtypes.GoogleSearchRetrieval()
293
- ))
294
- except Exception as e:
295
- # Do not break the request if tool construction fails
296
- self.window.core.debug.log(e)
297
-
298
- # Code Execution tool
299
- if cfg.get("remote_tools.google.code_interpreter") and "image" not in model.id:
300
- try:
301
- tools.append(gtypes.Tool(code_execution=gtypes.ToolCodeExecution))
302
- except Exception as e:
303
- self.window.core.debug.log(e)
304
-
305
- # URL Context tool
306
- if cfg.get("remote_tools.google.url_ctx") and "image" not in model.id:
307
- try:
308
- # Supported on Gemini 2.x+ models (not on 1.5)
309
- if not model_id.startswith("gemini-1.5") and not model_id.startswith("models/gemini-1.5"):
310
- tools.append(gtypes.Tool(url_context=gtypes.UrlContext))
311
- except Exception as e:
312
- self.window.core.debug.log(e)
313
-
314
- return tools
315
-
316
278
  def setup_env(self) -> bool:
317
279
  """
318
280
  Setup environment variables for VertexAI via Google GenAI API