pygpt-net 2.7.6__py3-none-any.whl → 2.7.8__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 (120) hide show
  1. pygpt_net/CHANGELOG.txt +13 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +5 -1
  4. pygpt_net/controller/assistant/batch.py +2 -2
  5. pygpt_net/controller/assistant/files.py +7 -6
  6. pygpt_net/controller/assistant/threads.py +0 -0
  7. pygpt_net/controller/chat/command.py +0 -0
  8. pygpt_net/controller/chat/remote_tools.py +3 -9
  9. pygpt_net/controller/chat/stream.py +2 -2
  10. pygpt_net/controller/chat/{handler/worker.py → stream_worker.py} +13 -35
  11. pygpt_net/controller/dialogs/confirm.py +35 -58
  12. pygpt_net/controller/lang/mapping.py +9 -9
  13. pygpt_net/controller/remote_store/{google/batch.py → batch.py} +209 -252
  14. pygpt_net/controller/remote_store/remote_store.py +982 -13
  15. pygpt_net/core/command/command.py +0 -0
  16. pygpt_net/core/db/viewer.py +1 -1
  17. pygpt_net/core/debug/models.py +2 -2
  18. pygpt_net/core/realtime/worker.py +3 -1
  19. pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
  20. pygpt_net/core/remote_store/anthropic/files.py +211 -0
  21. pygpt_net/core/remote_store/anthropic/store.py +208 -0
  22. pygpt_net/core/remote_store/openai/store.py +5 -4
  23. pygpt_net/core/remote_store/remote_store.py +5 -1
  24. pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
  25. pygpt_net/core/remote_store/xai/files.py +225 -0
  26. pygpt_net/core/remote_store/xai/store.py +219 -0
  27. pygpt_net/data/config/config.json +18 -5
  28. pygpt_net/data/config/models.json +193 -4
  29. pygpt_net/data/config/settings.json +179 -36
  30. pygpt_net/data/icons/folder_eye.svg +1 -0
  31. pygpt_net/data/icons/folder_eye_filled.svg +1 -0
  32. pygpt_net/data/icons/folder_open.svg +1 -0
  33. pygpt_net/data/icons/folder_open_filled.svg +1 -0
  34. pygpt_net/data/locale/locale.de.ini +6 -3
  35. pygpt_net/data/locale/locale.en.ini +46 -12
  36. pygpt_net/data/locale/locale.es.ini +6 -3
  37. pygpt_net/data/locale/locale.fr.ini +6 -3
  38. pygpt_net/data/locale/locale.it.ini +6 -3
  39. pygpt_net/data/locale/locale.pl.ini +7 -4
  40. pygpt_net/data/locale/locale.uk.ini +6 -3
  41. pygpt_net/data/locale/locale.zh.ini +6 -3
  42. pygpt_net/icons.qrc +4 -0
  43. pygpt_net/icons_rc.py +282 -138
  44. pygpt_net/plugin/cmd_mouse_control/worker.py +2 -1
  45. pygpt_net/plugin/cmd_mouse_control/worker_sandbox.py +2 -1
  46. pygpt_net/provider/api/anthropic/__init__.py +10 -3
  47. pygpt_net/provider/api/anthropic/chat.py +342 -11
  48. pygpt_net/provider/api/anthropic/computer.py +844 -0
  49. pygpt_net/provider/api/anthropic/remote_tools.py +172 -0
  50. pygpt_net/provider/api/anthropic/store.py +307 -0
  51. pygpt_net/{controller/chat/handler/anthropic_stream.py → provider/api/anthropic/stream.py} +99 -10
  52. pygpt_net/provider/api/anthropic/tools.py +32 -77
  53. pygpt_net/provider/api/anthropic/utils.py +30 -0
  54. pygpt_net/{controller/chat/handler → provider/api/anthropic/worker}/__init__.py +0 -0
  55. pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
  56. pygpt_net/provider/api/google/chat.py +62 -9
  57. pygpt_net/provider/api/google/store.py +124 -3
  58. pygpt_net/{controller/chat/handler/google_stream.py → provider/api/google/stream.py} +92 -25
  59. pygpt_net/provider/api/google/utils.py +185 -0
  60. pygpt_net/provider/api/google/worker/importer.py +16 -28
  61. pygpt_net/provider/api/langchain/__init__.py +0 -0
  62. pygpt_net/{controller/chat/handler/langchain_stream.py → provider/api/langchain/stream.py} +1 -1
  63. pygpt_net/provider/api/llama_index/__init__.py +0 -0
  64. pygpt_net/{controller/chat/handler/llamaindex_stream.py → provider/api/llama_index/stream.py} +1 -1
  65. pygpt_net/provider/api/openai/assistants.py +2 -2
  66. pygpt_net/provider/api/openai/image.py +2 -2
  67. pygpt_net/provider/api/openai/store.py +4 -1
  68. pygpt_net/{controller/chat/handler/openai_stream.py → provider/api/openai/stream.py} +1 -1
  69. pygpt_net/provider/api/openai/utils.py +69 -3
  70. pygpt_net/provider/api/openai/worker/importer.py +19 -61
  71. pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
  72. pygpt_net/provider/api/x_ai/__init__.py +138 -15
  73. pygpt_net/provider/api/x_ai/audio.py +43 -11
  74. pygpt_net/provider/api/x_ai/chat.py +92 -4
  75. pygpt_net/provider/api/x_ai/image.py +149 -47
  76. pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
  77. pygpt_net/provider/api/x_ai/realtime/client.py +1825 -0
  78. pygpt_net/provider/api/x_ai/realtime/realtime.py +198 -0
  79. pygpt_net/provider/api/x_ai/{remote.py → remote_tools.py} +183 -70
  80. pygpt_net/provider/api/x_ai/responses.py +507 -0
  81. pygpt_net/provider/api/x_ai/store.py +610 -0
  82. pygpt_net/{controller/chat/handler/xai_stream.py → provider/api/x_ai/stream.py} +42 -10
  83. pygpt_net/provider/api/x_ai/tools.py +59 -8
  84. pygpt_net/{controller/chat/handler → provider/api/x_ai}/utils.py +1 -2
  85. pygpt_net/provider/api/x_ai/vision.py +1 -4
  86. pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
  87. pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
  88. pygpt_net/provider/audio_output/xai_tts.py +325 -0
  89. pygpt_net/provider/core/config/patch.py +39 -3
  90. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
  91. pygpt_net/provider/core/model/patch.py +39 -1
  92. pygpt_net/tools/image_viewer/tool.py +334 -34
  93. pygpt_net/tools/image_viewer/ui/dialogs.py +319 -22
  94. pygpt_net/tools/text_editor/ui/dialogs.py +3 -2
  95. pygpt_net/tools/text_editor/ui/widgets.py +0 -0
  96. pygpt_net/ui/dialog/assistant.py +1 -1
  97. pygpt_net/ui/dialog/plugins.py +13 -5
  98. pygpt_net/ui/dialog/remote_store.py +552 -0
  99. pygpt_net/ui/dialogs.py +3 -5
  100. pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
  101. pygpt_net/ui/menu/tools.py +6 -13
  102. pygpt_net/ui/widget/dialog/base.py +16 -5
  103. pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
  104. pygpt_net/ui/widget/element/button.py +4 -4
  105. pygpt_net/ui/widget/image/display.py +2 -2
  106. pygpt_net/ui/widget/lists/context.py +2 -2
  107. pygpt_net/ui/widget/textarea/editor.py +0 -0
  108. {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +15 -2
  109. {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +107 -89
  110. pygpt_net/controller/remote_store/google/store.py +0 -615
  111. pygpt_net/controller/remote_store/openai/batch.py +0 -524
  112. pygpt_net/controller/remote_store/openai/store.py +0 -699
  113. pygpt_net/ui/dialog/remote_store_google.py +0 -539
  114. pygpt_net/ui/dialog/remote_store_openai.py +0 -539
  115. pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
  116. pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
  117. pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
  118. {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
  119. {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
  120. {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/entry_points.txt +0 -0
File without changes
@@ -196,7 +196,7 @@ class Viewer:
196
196
  try:
197
197
  value = int(value)
198
198
  except:
199
- raise ValueError(f"Invalid _id value for column {field}")
199
+ pass
200
200
 
201
201
  if self.is_auto_backup():
202
202
  backup_path = self.database.make_backup()
@@ -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.09.14 20:00:00 #
9
+ # Updated Date: 2026.01.05 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -24,7 +24,7 @@ class ModelsDebug:
24
24
  def update(self):
25
25
  """Update debug window."""
26
26
  debug = self.window.core.debug
27
- models_controller = self.window.controller.models
27
+ models_controller = self.window.controller.model
28
28
  models_core = self.window.core.models
29
29
  command_core = self.window.core.command
30
30
  config_core = self.window.core.config
@@ -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.08.30 06:00:00 #
9
+ # Updated Date: 2026.01.06 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import asyncio
@@ -63,6 +63,8 @@ class RealtimeWorker(QRunnable):
63
63
  return self.window.core.api.google.realtime.handler
64
64
  elif provider == "openai":
65
65
  return self.window.core.api.openai.realtime.handler
66
+ elif provider == "x_ai":
67
+ return self.window.core.api.xai.realtime.handler
66
68
  else:
67
69
  raise RuntimeError(f"Unsupported realtime provider: {provider}")
68
70
 
@@ -8,5 +8,4 @@
8
8
  # Created By : Marcin Szczygliński #
9
9
  # Updated Date: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
-
12
11
  from .store import *
@@ -0,0 +1,211 @@
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: 2026.01.05 17:00:00 #
10
+ # ================================================== #
11
+
12
+ from typing import Optional, List, Dict, Union
13
+
14
+ from packaging.version import Version
15
+
16
+ from pygpt_net.item.assistant import AssistantItem
17
+ from pygpt_net.item.store import RemoteFileItem
18
+ from pygpt_net.provider.core.remote_file.db_sqlite import DbSqliteProvider
19
+
20
+
21
+ class Files:
22
+
23
+ PROVIDER_NAME = "anthropic"
24
+ DEFAULT_STORE_ID = "files"
25
+
26
+ def __init__(self, window=None):
27
+ """
28
+ Anthropic remote files core (workspace Files API)
29
+
30
+ :param window: Window instance
31
+ """
32
+ self.window = window
33
+ self.provider = DbSqliteProvider(window)
34
+ self.items: Dict[str, RemoteFileItem] = {}
35
+
36
+ def install(self):
37
+ self.provider.install()
38
+
39
+ def patch(self, app_version: Version) -> bool:
40
+ return self.provider.patch(app_version)
41
+
42
+ def get(self, id: str) -> Optional[RemoteFileItem]:
43
+ if id in self.items:
44
+ return self.items[id]
45
+ return None
46
+
47
+ def get_ids(self) -> List[str]:
48
+ return list(self.items.keys())
49
+
50
+ def get_all(self) -> Dict[str, RemoteFileItem]:
51
+ return self.items
52
+
53
+ def get_id_by_idx_all(self, idx: int) -> str:
54
+ return list(self.items.keys())[idx]
55
+
56
+ def get_by_idx(self, idx: int) -> str:
57
+ items = self.items
58
+ return list(items.keys())[idx]
59
+
60
+ def has(self, id: str) -> bool:
61
+ return id in self.items
62
+
63
+ def create(
64
+ self,
65
+ assistant: AssistantItem,
66
+ thread_id: str,
67
+ file_id: str,
68
+ name: str,
69
+ path: str,
70
+ size: int) -> Optional[RemoteFileItem]:
71
+ """
72
+ Not used in the Anthropic path (kept for parity).
73
+ """
74
+ file = RemoteFileItem()
75
+ file.id = file_id
76
+ file.file_id = file_id
77
+ file.thread_id = thread_id or ""
78
+ file.provider = self.PROVIDER_NAME
79
+ file.name = name
80
+ file.path = path
81
+ file.size = size or 0
82
+ file.store_id = self.DEFAULT_STORE_ID
83
+ file.record_id = self.provider.create(file)
84
+ self.items[file.id] = file
85
+ return file
86
+
87
+ def update(self, file: RemoteFileItem) -> Optional[RemoteFileItem]:
88
+ self.items[file.id] = file
89
+ self.provider.save(file)
90
+ return file
91
+
92
+ def get_names(self) -> Dict[str, str]:
93
+ names = {}
94
+ for id in self.items:
95
+ file = self.items[id]
96
+ names[id] = file.name
97
+ return names
98
+
99
+ def get_by_store_or_thread(self, store_id: str, thread_id: str) -> Dict[str, RemoteFileItem]:
100
+ return self.provider.get_by_store_or_thread(store_id, thread_id)
101
+
102
+ def count_by_store_or_thread(self, store_id: str, thread_id: str) -> int:
103
+ return self.provider.count_by_store_or_thread(store_id, thread_id)
104
+
105
+ def get_file_by_idx(self, idx: int, store_id: str, thread_id: str) -> Optional[RemoteFileItem]:
106
+ files = self.get_by_store_or_thread(store_id, thread_id)
107
+ if idx >= len(files):
108
+ return None
109
+ return list(files.values())[idx]
110
+
111
+ def get_file_id_by_idx(self, idx: int, store_id: str, thread_id: str) -> Optional[str]:
112
+ file = self.get_file_by_idx(idx, store_id, thread_id)
113
+ if file is None:
114
+ return None
115
+ return file.file_id
116
+
117
+ def get_all_by_file_id(self, file_id: str) -> dict:
118
+ return self.provider.get_all_by_file_id(file_id)
119
+
120
+ def delete(self, file: Union[RemoteFileItem, list]) -> bool:
121
+ files = file if isinstance(file, list) else [file]
122
+ for f in files:
123
+ file_id = f.file_id
124
+ try:
125
+ self.window.core.api.anthropic.store.remove_file(file_id)
126
+ except Exception as e:
127
+ self.window.core.debug.log("Failed to delete remote file: " + str(e))
128
+ self.provider.delete_by_id(f.record_id)
129
+ if f.record_id in self.items:
130
+ del self.items[f.record_id]
131
+ return True
132
+
133
+ def delete_by_file_id(self, file_id: str) -> bool:
134
+ res = self.provider.delete_by_file_id(file_id)
135
+ if res:
136
+ to_delete = []
137
+ for id in self.items:
138
+ if self.items[id].file_id == file_id:
139
+ to_delete.append(id)
140
+ for id in to_delete:
141
+ del self.items[id]
142
+ return res
143
+
144
+ def on_store_deleted(self, store_id: str):
145
+ self.provider.clear_store_from_files(store_id)
146
+
147
+ def on_all_stores_deleted(self):
148
+ self.provider.clear_all_stores_from_files(self.PROVIDER_NAME)
149
+
150
+ def rename(self, record_id: int, name: str) -> bool:
151
+ self.provider.rename_file(record_id, name)
152
+ if record_id in self.items:
153
+ self.items[record_id].name = name
154
+ return True
155
+
156
+ def truncate(self, store_id: Optional[str] = None) -> bool:
157
+ self.window.core.api.anthropic.store.remove_files()
158
+ return self.truncate_local(store_id)
159
+
160
+ def truncate_local(self, store_id: Optional[str] = None) -> bool:
161
+ if store_id is not None:
162
+ self.provider.truncate_by_store(store_id)
163
+ else:
164
+ self.provider.truncate_all(self.PROVIDER_NAME)
165
+ self.items = {}
166
+ return True
167
+
168
+ def import_from_store(self, store_id: str) -> bool:
169
+ files = self.window.core.api.anthropic.store.import_files()
170
+ for f in files:
171
+ pass
172
+ return True
173
+
174
+ def insert(self, store_id: str, data) -> RemoteFileItem:
175
+ """
176
+ Insert a File into local DB
177
+
178
+ :param store_id: pseudo store id ('files')
179
+ :param data: file object from API
180
+ """
181
+ file = RemoteFileItem()
182
+ file.id = getattr(data, "id", None) or getattr(data, "name", None)
183
+ file.file_id = getattr(data, "id", None) or getattr(data, "name", None)
184
+ file.thread_id = ""
185
+ file.name = getattr(data, "filename", None) or getattr(data, "name", "") or file.file_id
186
+ file.provider = self.PROVIDER_NAME
187
+ file.path = file.name
188
+ try:
189
+ size = getattr(data, "size_bytes", None)
190
+ if size is None and hasattr(data, "size"):
191
+ size = getattr(data, "size")
192
+ file.size = int(size or 0)
193
+ except Exception:
194
+ file.size = 0
195
+ file.store_id = self.DEFAULT_STORE_ID
196
+ file.record_id = self.provider.create(file)
197
+ self.items[file.id] = file
198
+ return file
199
+
200
+ def load(self):
201
+ self.items = self.provider.load_all(self.PROVIDER_NAME)
202
+ self.sort_items()
203
+
204
+ def sort_items(self):
205
+ return
206
+
207
+ def save(self):
208
+ self.provider.save_all(self.items)
209
+
210
+ def get_version(self) -> str:
211
+ return self.provider.get_version()
@@ -0,0 +1,208 @@
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: 2026.01.05 17:00:00 #
10
+ # ================================================== #
11
+
12
+ import datetime
13
+ from typing import Optional, List, Dict, Any
14
+
15
+ from packaging.version import Version
16
+
17
+ from pygpt_net.item.store import RemoteStoreItem
18
+ from pygpt_net.provider.core.remote_store.db_sqlite import DbSqliteProvider
19
+
20
+ from .files import Files
21
+
22
+
23
+ class Store:
24
+ """
25
+ Anthropic Files API "store" adapter.
26
+ Anthropic does not have vector stores; we expose a single workspace-level pseudo store.
27
+ """
28
+
29
+ PROVIDER_NAME = "anthropic"
30
+ DEFAULT_STORE_ID = "files"
31
+ DEFAULT_STORE_NAME = "Files"
32
+
33
+ def __init__(self, window=None):
34
+ """
35
+ Anthropic Files workspace core
36
+
37
+ :param window: Window instance
38
+ """
39
+ self.window = window
40
+ self.provider = DbSqliteProvider(window)
41
+ self.files = Files(window)
42
+ self.items: Dict[str, RemoteStoreItem] = {}
43
+
44
+ def install(self):
45
+ """Install provider data"""
46
+ self.provider.install()
47
+ self.files.install()
48
+
49
+ def patch(self, app_version: Version) -> bool:
50
+ """Patch provider data"""
51
+ res1 = self.files.patch(app_version)
52
+ res2 = self.provider.patch(app_version)
53
+ return res1 or res2
54
+
55
+ def get(self, id: str) -> RemoteStoreItem:
56
+ if id in self.items:
57
+ return self.items[id]
58
+
59
+ def get_ids(self) -> List[str]:
60
+ return list(self.items.keys())
61
+
62
+ def get_all(self) -> Dict[str, RemoteStoreItem]:
63
+ return self.items
64
+
65
+ def get_id_by_idx_all(self, idx: int) -> str:
66
+ return list(self.items.keys())[idx]
67
+
68
+ def get_by_idx(self, idx: int) -> str:
69
+ items = self.items
70
+ return list(items.keys())[idx]
71
+
72
+ def has(self, id: str) -> bool:
73
+ return id in self.items
74
+
75
+ def _ensure_default(self) -> RemoteStoreItem:
76
+ """Ensure default pseudo-store exists locally."""
77
+ if self.DEFAULT_STORE_ID in self.items:
78
+ return self.items[self.DEFAULT_STORE_ID]
79
+ store = RemoteStoreItem()
80
+ store.id = self.DEFAULT_STORE_ID
81
+ store.name = self.DEFAULT_STORE_NAME
82
+ store.provider = self.PROVIDER_NAME
83
+ store.is_thread = False
84
+ store.record_id = self.provider.create(store)
85
+ self.items[store.id] = store
86
+ return store
87
+
88
+ def create(self, name: Optional[str] = None) -> Optional[RemoteStoreItem]:
89
+ """
90
+ Create workspace-level pseudo-store (idempotent).
91
+
92
+ :param name: local alias
93
+ :return: store item
94
+ """
95
+ store = self._ensure_default()
96
+ if name:
97
+ store.name = name
98
+ self.provider.save(store)
99
+ return store
100
+
101
+ def update(self, store: RemoteStoreItem) -> Optional[RemoteStoreItem]:
102
+ """
103
+ Update local store metadata (no remote update).
104
+ """
105
+ self.items[store.id] = store
106
+ self.provider.save(store)
107
+ return store
108
+
109
+ def get_status_data(self, id: str):
110
+ """
111
+ Compute workspace status from Files API
112
+ """
113
+ status = {}
114
+ stats = self.window.core.api.anthropic.store.get_files_stats()
115
+ if stats is not None:
116
+ status = {
117
+ "status": "ready",
118
+ "usage_bytes": int(stats.get("total_bytes", 0) or 0),
119
+ "expires_at": None,
120
+ "last_active_at": int(datetime.datetime.now().timestamp()),
121
+ "file_counts": {
122
+ "in_progress": 0,
123
+ "completed": int(stats.get("count", 0) or 0),
124
+ "cancelled": 0,
125
+ "failed": 0,
126
+ "total": int(stats.get("count", 0) or 0),
127
+ },
128
+ "expires_after": None,
129
+ "remote_display_name": self.items.get(id, RemoteStoreItem()).name if id in self.items else self.DEFAULT_STORE_NAME,
130
+ }
131
+ return status, None
132
+
133
+ def update_status(self, id: str):
134
+ """
135
+ Update pseudo-store status
136
+ """
137
+ self._ensure_default()
138
+ store = self.items[id]
139
+ status, _ = self.get_status_data(id)
140
+ self.append_status(store, status)
141
+ self.update(store)
142
+
143
+ def append_status(self, store: RemoteStoreItem, status: Dict[str, Any]):
144
+ now = datetime.datetime.now()
145
+ ts = int(now.timestamp())
146
+ status["__last_refresh__"] = now.strftime("%Y-%m-%d %H:%M:%S")
147
+ store.status = status
148
+ store.last_sync = ts
149
+ if "status" in status:
150
+ store.last_status = status["status"]
151
+ if "usage_bytes" in status:
152
+ store.usage_bytes = status["usage_bytes"]
153
+ if "file_counts" in status:
154
+ store.num_files = status["file_counts"]["total"]
155
+ if "last_active_at" in status and status["last_active_at"]:
156
+ store.last_active = int(status["last_active_at"])
157
+
158
+ def get_names(self) -> Dict[str, str]:
159
+ names = {}
160
+ for id in self.items:
161
+ store = self.items[id]
162
+ names[id] = store.name
163
+ return names
164
+
165
+ def delete(self, id: str) -> bool:
166
+ if id in self.items:
167
+ store = self.items[id]
168
+ self.provider.delete_by_id(store.record_id)
169
+ del self.items[id]
170
+ return True
171
+ return False
172
+
173
+ def import_items(self, items: Dict[str, RemoteStoreItem]):
174
+ self.items = items
175
+ for item in items.values():
176
+ item.provider = self.PROVIDER_NAME
177
+ item.record_id = self.provider.create(item)
178
+
179
+ def clear(self):
180
+ self.truncate()
181
+
182
+ def is_hidden(self, id: str) -> bool:
183
+ return False
184
+
185
+ def truncate(self) -> bool:
186
+ self.provider.truncate(self.PROVIDER_NAME)
187
+ self.items = {}
188
+ return True
189
+
190
+ def load(self):
191
+ self.items = self.provider.load_all(self.PROVIDER_NAME)
192
+ if self.DEFAULT_STORE_ID not in self.items:
193
+ # Ensure default exists
194
+ self._ensure_default()
195
+ self.sort_items()
196
+
197
+ def load_all(self):
198
+ self.load()
199
+ self.files.load()
200
+
201
+ def sort_items(self):
202
+ pass
203
+
204
+ def save(self):
205
+ self.provider.save_all(self.items)
206
+
207
+ def get_version(self) -> str:
208
+ return self.provider.get_version()
@@ -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: 2026.01.02 20:00:00 #
9
+ # Updated Date: 2026.01.05 17:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -108,13 +108,14 @@ class Store:
108
108
  """
109
109
  return id in self.items
110
110
 
111
- def create(self) -> Optional[RemoteStoreItem]:
111
+ def create(self, name: Optional[str] = None) -> Optional[RemoteStoreItem]:
112
112
  """
113
113
  Create new store
114
114
 
115
+ :param name: store name
115
116
  :return: store item
116
117
  """
117
- name = "New vector store"
118
+ # name = "New vector store"
118
119
  vector_store = self.window.core.api.openai.store.create_store(name, 0)
119
120
  if vector_store is None:
120
121
  return None
@@ -275,7 +276,7 @@ class Store:
275
276
  :return: True if store is hidden
276
277
  """
277
278
  if id in self.items:
278
- if (self.window.core.config.get("remote_store.openai.hide_threads")
279
+ if (self.window.core.config.get("remote_store.hide_threads")
279
280
  and (self.items[id].name is None or self.items[id].name == "")):
280
281
  return True
281
282
  return False
@@ -11,6 +11,8 @@
11
11
 
12
12
  from .openai import Store as OpenAIStore
13
13
  from .google import Store as GoogleStore
14
+ from .anthropic import Store as AnthropicStore
15
+ from .xai import Store as XAIStore
14
16
 
15
17
  class RemoteStore:
16
18
  def __init__(self, window=None):
@@ -21,4 +23,6 @@ class RemoteStore:
21
23
  """
22
24
  self.window = window
23
25
  self.openai = OpenAIStore(self.window)
24
- self.google = GoogleStore(self.window)
26
+ self.google = GoogleStore(self.window)
27
+ self.anthropic = AnthropicStore(self.window)
28
+ self.xai = XAIStore(self.window)
@@ -8,5 +8,4 @@
8
8
  # Created By : Marcin Szczygliński #
9
9
  # Updated Date: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
-
12
11
  from .store import *